msm: camera: icp: Add LX7 driver
Add initial support for the LX7 processor. Support for firmware loading and processor boot are still pending. Note this also cleans up some descriptions in struct cam_icp_hw_mgr that were left over when the debugfs entries were renamed. CRs-Fixed: 2722486 Change-Id: I626cc27e26e1ebac8ec6b4509ab5da2a013457b1 Signed-off-by: Karthik Anantha Ram <kartanan@codeaurora.org>
This commit is contained in:
3
Kbuild
3
Kbuild
@@ -149,6 +149,9 @@ camera-$(CONFIG_SPECTRA_ICP) += \
|
|||||||
drivers/cam_icp/icp_hw/a5_hw/a5_dev.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_core.o \
|
||||||
drivers/cam_icp/icp_hw/a5_hw/a5_soc.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/bps_hw/bps_dev.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_core.o \
|
||||||
drivers/cam_icp/icp_hw/bps_hw/bps_soc.o \
|
drivers/cam_icp/icp_hw/bps_hw/bps_soc.o \
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
@@ -336,15 +336,15 @@ int cam_a5_init_hw(void *device_priv,
|
|||||||
cpas_vote.axi_vote.axi_path[0].transac_type =
|
cpas_vote.axi_vote.axi_path[0].transac_type =
|
||||||
CAM_ICP_DEFAULT_AXI_TRANSAC;
|
CAM_ICP_DEFAULT_AXI_TRANSAC;
|
||||||
cpas_vote.axi_vote.axi_path[0].camnoc_bw =
|
cpas_vote.axi_vote.axi_path[0].camnoc_bw =
|
||||||
CAM_ICP_A5_BW_BYTES_VOTE;
|
CAM_ICP_BW_BYTES_VOTE;
|
||||||
cpas_vote.axi_vote.axi_path[0].mnoc_ab_bw =
|
cpas_vote.axi_vote.axi_path[0].mnoc_ab_bw =
|
||||||
CAM_ICP_A5_BW_BYTES_VOTE;
|
CAM_ICP_BW_BYTES_VOTE;
|
||||||
cpas_vote.axi_vote.axi_path[0].mnoc_ib_bw =
|
cpas_vote.axi_vote.axi_path[0].mnoc_ib_bw =
|
||||||
CAM_ICP_A5_BW_BYTES_VOTE;
|
CAM_ICP_BW_BYTES_VOTE;
|
||||||
cpas_vote.axi_vote.axi_path[0].ddr_ab_bw =
|
cpas_vote.axi_vote.axi_path[0].ddr_ab_bw =
|
||||||
CAM_ICP_A5_BW_BYTES_VOTE;
|
CAM_ICP_BW_BYTES_VOTE;
|
||||||
cpas_vote.axi_vote.axi_path[0].ddr_ib_bw =
|
cpas_vote.axi_vote.axi_path[0].ddr_ib_bw =
|
||||||
CAM_ICP_A5_BW_BYTES_VOTE;
|
CAM_ICP_BW_BYTES_VOTE;
|
||||||
|
|
||||||
rc = cam_cpas_start(core_info->cpas_handle,
|
rc = cam_cpas_start(core_info->cpas_handle,
|
||||||
&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
|
&cpas_vote.ahb_vote, &cpas_vote.axi_vote);
|
||||||
@@ -558,6 +558,7 @@ irqreturn_t cam_a5_irq(int irq_num, void *data)
|
|||||||
struct cam_a5_device_core_info *core_info = NULL;
|
struct cam_a5_device_core_info *core_info = NULL;
|
||||||
struct cam_a5_device_hw_info *hw_info = NULL;
|
struct cam_a5_device_hw_info *hw_info = NULL;
|
||||||
uint32_t irq_status = 0;
|
uint32_t irq_status = 0;
|
||||||
|
bool recover = false;
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
CAM_ERR(CAM_ICP, "Invalid cam_dev_info or query_cap args");
|
CAM_ERR(CAM_ICP, "Invalid cam_dev_info or query_cap args");
|
||||||
@@ -586,11 +587,13 @@ irqreturn_t cam_a5_irq(int irq_num, void *data)
|
|||||||
if ((irq_status & A5_WDT_0) ||
|
if ((irq_status & A5_WDT_0) ||
|
||||||
(irq_status & A5_WDT_1)) {
|
(irq_status & A5_WDT_1)) {
|
||||||
CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5");
|
CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5");
|
||||||
|
recover = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
spin_lock(&a5_dev->hw_lock);
|
spin_lock(&a5_dev->hw_lock);
|
||||||
if (core_info->irq_cb.cb)
|
if (core_info->irq_cb.cb)
|
||||||
core_info->irq_cb.cb(core_info->irq_cb.data, irq_status);
|
core_info->irq_cb.cb(core_info->irq_cb.data,
|
||||||
|
recover);
|
||||||
spin_unlock(&a5_dev->hw_lock);
|
spin_unlock(&a5_dev->hw_lock);
|
||||||
|
|
||||||
return IRQ_HANDLED;
|
return IRQ_HANDLED;
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
@@ -38,6 +38,7 @@
|
|||||||
#include "cam_req_mgr_workq.h"
|
#include "cam_req_mgr_workq.h"
|
||||||
#include "cam_mem_mgr.h"
|
#include "cam_mem_mgr.h"
|
||||||
#include "a5_core.h"
|
#include "a5_core.h"
|
||||||
|
#include "lx7_core.h"
|
||||||
#include "hfi_sys_defs.h"
|
#include "hfi_sys_defs.h"
|
||||||
#include "cam_debug_util.h"
|
#include "cam_debug_util.h"
|
||||||
#include "cam_soc_util.h"
|
#include "cam_soc_util.h"
|
||||||
@@ -59,6 +60,12 @@ static const struct hfi_ops hfi_a5_ops = {
|
|||||||
.iface_addr = cam_a5_iface_addr,
|
.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 struct cam_icp_hw_mgr icp_hw_mgr;
|
||||||
|
|
||||||
static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl);
|
static void cam_icp_mgr_process_dbg_buf(unsigned int debug_lvl);
|
||||||
@@ -2653,9 +2660,8 @@ static int32_t cam_icp_mgr_process_msg(void *priv, void *data)
|
|||||||
|
|
||||||
cam_icp_mgr_process_dbg_buf(icp_hw_mgr.icp_dbg_lvl);
|
cam_icp_mgr_process_dbg_buf(icp_hw_mgr.icp_dbg_lvl);
|
||||||
|
|
||||||
if ((task_data->irq_status & A5_WDT_0) ||
|
if (task_data->recover) {
|
||||||
(task_data->irq_status & A5_WDT_1)) {
|
CAM_ERR_RATE_LIMIT(CAM_ICP, "issuing device recovery...");
|
||||||
CAM_ERR_RATE_LIMIT(CAM_ICP, "watch dog interrupt from A5");
|
|
||||||
|
|
||||||
rc = cam_icp_mgr_trigger_recovery(hw_mgr);
|
rc = cam_icp_mgr_trigger_recovery(hw_mgr);
|
||||||
}
|
}
|
||||||
@@ -2663,7 +2669,7 @@ static int32_t cam_icp_mgr_process_msg(void *priv, void *data)
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cam_icp_hw_mgr_cb(void *data, uint32_t irq_status)
|
static int32_t cam_icp_hw_mgr_cb(void *data, bool recover)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
@@ -2686,7 +2692,7 @@ static int cam_icp_hw_mgr_cb(void *data, uint32_t irq_status)
|
|||||||
|
|
||||||
task_data = (struct hfi_msg_work_data *)task->payload;
|
task_data = (struct hfi_msg_work_data *)task->payload;
|
||||||
task_data->data = hw_mgr;
|
task_data->data = hw_mgr;
|
||||||
task_data->irq_status = irq_status;
|
task_data->recover = recover;
|
||||||
task_data->type = ICP_WORKQ_TASK_MSG_TYPE;
|
task_data->type = ICP_WORKQ_TASK_MSG_TYPE;
|
||||||
task->process_cb = cam_icp_mgr_process_msg;
|
task->process_cb = cam_icp_mgr_process_msg;
|
||||||
rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
|
rc = cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr,
|
||||||
@@ -3726,6 +3732,9 @@ static int cam_icp_mgr_hfi_init(struct cam_icp_hw_mgr *hw_mgr)
|
|||||||
hfi_mem.io_mem2.len = 0x0;
|
hfi_mem.io_mem2.len = 0x0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (icp_dev_intf->hw_type == CAM_ICP_DEV_LX7)
|
||||||
|
hfi_ops = &hfi_lx7_ops;
|
||||||
|
else
|
||||||
hfi_ops = &hfi_a5_ops;
|
hfi_ops = &hfi_a5_ops;
|
||||||
|
|
||||||
return cam_hfi_init(&hfi_mem, hfi_ops, icp_dev, 0);
|
return cam_hfi_init(&hfi_mem, hfi_ops, icp_dev, 0);
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CAM_ICP_HW_MGR_H
|
#ifndef CAM_ICP_HW_MGR_H
|
||||||
@@ -115,12 +115,12 @@ struct hfi_cmd_work_data {
|
|||||||
* struct hfi_msg_work_data
|
* struct hfi_msg_work_data
|
||||||
* @type: Task type
|
* @type: Task type
|
||||||
* @data: Pointer to message data
|
* @data: Pointer to message data
|
||||||
* @irq_status: IRQ status
|
* @recover: Device needs recovery
|
||||||
*/
|
*/
|
||||||
struct hfi_msg_work_data {
|
struct hfi_msg_work_data {
|
||||||
uint32_t type;
|
uint32_t type;
|
||||||
void *data;
|
void *data;
|
||||||
uint32_t irq_status;
|
bool recover;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CAM_ICP_HW_INTF_H
|
#ifndef CAM_ICP_HW_INTF_H
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
enum cam_icp_hw_type {
|
enum cam_icp_hw_type {
|
||||||
CAM_ICP_DEV_A5,
|
CAM_ICP_DEV_A5,
|
||||||
|
CAM_ICP_DEV_LX7,
|
||||||
CAM_ICP_DEV_IPE,
|
CAM_ICP_DEV_IPE,
|
||||||
CAM_ICP_DEV_BPS,
|
CAM_ICP_DEV_BPS,
|
||||||
CAM_ICP_DEV_MAX,
|
CAM_ICP_DEV_MAX,
|
||||||
@@ -41,8 +42,8 @@ enum cam_icp_cmd_type {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct cam_icp_irq_cb {
|
struct cam_icp_irq_cb {
|
||||||
|
int32_t (*cb)(void *data, bool recover);
|
||||||
void *data;
|
void *data;
|
||||||
int (*cb)(void *data, uint32_t irq_status);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CAM_ICP_HW_MGR_INTF_H
|
#ifndef CAM_ICP_HW_MGR_INTF_H
|
||||||
@@ -14,7 +14,7 @@
|
|||||||
#define ICP_CLK_TURBO_HZ 600000000
|
#define ICP_CLK_TURBO_HZ 600000000
|
||||||
#define ICP_CLK_SVS_HZ 400000000
|
#define ICP_CLK_SVS_HZ 400000000
|
||||||
|
|
||||||
#define CAM_ICP_A5_BW_BYTES_VOTE 40000000
|
#define CAM_ICP_BW_BYTES_VOTE 40000000
|
||||||
|
|
||||||
#define CAM_ICP_CTX_MAX 54
|
#define CAM_ICP_CTX_MAX 54
|
||||||
|
|
||||||
|
391
drivers/cam_icp/icp_hw/lx7_hw/lx7_core.c
Normal file
391
drivers/cam_icp/icp_hw/lx7_hw/lx7_core.c
Normal file
@@ -0,0 +1,391 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/firmware.h>
|
||||||
|
#include <linux/of_address.h>
|
||||||
|
#include <linux/qcom_scm.h>
|
||||||
|
|
||||||
|
#include "cam_cpas_api.h"
|
||||||
|
#include "cam_debug_util.h"
|
||||||
|
#include "cam_hw.h"
|
||||||
|
#include "cam_hw_intf.h"
|
||||||
|
#include "cam_icp_hw_mgr_intf.h"
|
||||||
|
#include "cam_icp_hw_intf.h"
|
||||||
|
#include "hfi_intf.h"
|
||||||
|
#include "lx7_core.h"
|
||||||
|
#include "lx7_reg.h"
|
||||||
|
#include "lx7_soc.h"
|
||||||
|
|
||||||
|
#define TZ_STATE_RESUME 0
|
||||||
|
#define TZ_STATE_SUSPEND 1
|
||||||
|
|
||||||
|
#define LX7_FW_NAME "CAMERA_ICP.elf"
|
||||||
|
|
||||||
|
#define LX7_GEN_PURPOSE_REG_OFFSET 0x20
|
||||||
|
|
||||||
|
static int cam_lx7_ubwc_configure(struct cam_hw_soc_info *soc_info)
|
||||||
|
{
|
||||||
|
int i = 0, rc, ddr_type;
|
||||||
|
struct lx7_soc_info *soc_priv;
|
||||||
|
uint32_t ipe_ubwc_cfg[UBWC_CONFIG_MAX];
|
||||||
|
uint32_t bps_ubwc_cfg[UBWC_CONFIG_MAX];
|
||||||
|
|
||||||
|
if (!soc_info || !soc_info->soc_private) {
|
||||||
|
CAM_ERR(CAM_ICP, "invalid LX7 soc info");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
soc_priv = soc_info->soc_private;
|
||||||
|
|
||||||
|
ddr_type = of_fdt_get_ddrtype();
|
||||||
|
if (ddr_type == DDR_TYPE_LPDDR5 || ddr_type == DDR_TYPE_LPDDR5X)
|
||||||
|
i = 1;
|
||||||
|
|
||||||
|
ipe_ubwc_cfg[0] = soc_priv->ubwc_cfg.ipe_fetch[i];
|
||||||
|
ipe_ubwc_cfg[1] = soc_priv->ubwc_cfg.ipe_write[i];
|
||||||
|
|
||||||
|
bps_ubwc_cfg[0] = soc_priv->ubwc_cfg.bps_fetch[i];
|
||||||
|
bps_ubwc_cfg[1] = soc_priv->ubwc_cfg.bps_write[i];
|
||||||
|
|
||||||
|
rc = hfi_cmd_ubwc_config_ext(ipe_ubwc_cfg, bps_ubwc_cfg);
|
||||||
|
if (rc) {
|
||||||
|
CAM_ERR(CAM_ICP, "failed to write UBWC config rc=%d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cam_lx7_cpas_vote(struct cam_lx7_core_info *core_info,
|
||||||
|
struct cam_icp_cpas_vote *vote)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!core_info || !vote)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
if (vote->ahb_vote_valid) {
|
||||||
|
rc = cam_cpas_update_ahb_vote(core_info->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(core_info->cpas_handle,
|
||||||
|
&vote->axi_vote);
|
||||||
|
if (rc) {
|
||||||
|
CAM_ERR(CAM_ICP, "AXI vote update failed rc=%d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool cam_lx7_cpas_cb(uint32_t handle, void *user_data,
|
||||||
|
struct cam_cpas_irq_data *irq_data)
|
||||||
|
{
|
||||||
|
bool ret = false;
|
||||||
|
(void)user_data;
|
||||||
|
|
||||||
|
if (!irq_data)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
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 status=0x%08x",
|
||||||
|
irq_data->u.dec_err.decerr_status.value);
|
||||||
|
ret = true;
|
||||||
|
case CAM_CAMNOC_IRQ_IPE_BPS_UBWC_ENCODE_ERROR:
|
||||||
|
CAM_ERR_RATE_LIMIT(CAM_ICP,
|
||||||
|
"IPE/BPS UBWC encode error status=0x%08x",
|
||||||
|
irq_data->u.enc_err.encerr_status.value);
|
||||||
|
ret = true;
|
||||||
|
default:
|
||||||
|
CAM_ERR(CAM_ICP, "unhandled irq_type=%d", irq_data->irq_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cam_lx7_cpas_register(struct cam_hw_intf *lx7_intf)
|
||||||
|
{
|
||||||
|
struct cam_cpas_register_params params;
|
||||||
|
struct cam_hw_info *lx7_info;
|
||||||
|
struct cam_lx7_core_info *core_info;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!lx7_intf)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
lx7_info = lx7_intf->hw_priv;
|
||||||
|
|
||||||
|
params.dev = lx7_info->soc_info.dev;
|
||||||
|
params.cell_index = lx7_intf->hw_idx;
|
||||||
|
params.cam_cpas_client_cb = cam_lx7_cpas_cb;
|
||||||
|
params.userdata = NULL;
|
||||||
|
|
||||||
|
strlcpy(params.identifier, "icp", CAM_HW_IDENTIFIER_LENGTH);
|
||||||
|
|
||||||
|
rc = cam_cpas_register_client(¶ms);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
core_info = lx7_info->core_info;
|
||||||
|
core_info->cpas_handle = params.client_handle;
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cam_lx7_cpas_unregister(struct cam_hw_intf *lx7_intf)
|
||||||
|
{
|
||||||
|
struct cam_hw_info *lx7_info;
|
||||||
|
struct cam_lx7_core_info *core_info;
|
||||||
|
|
||||||
|
if (!lx7_intf)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
lx7_info = lx7_intf->hw_priv;
|
||||||
|
core_info = lx7_info->core_info;
|
||||||
|
|
||||||
|
return cam_cpas_unregister_client(core_info->cpas_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __lx7_cpas_start(struct cam_lx7_core_info *core_info,
|
||||||
|
struct cam_icp_cpas_vote *vote)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!core_info || core_info->cpas_start)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
rc = cam_cpas_start(core_info->cpas_handle,
|
||||||
|
&vote->ahb_vote, &vote->axi_vote);
|
||||||
|
if (rc) {
|
||||||
|
CAM_ERR(CAM_ICP, "failed to start cpas rc=%d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
core_info->cpas_start = true;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cam_lx7_cpas_start(struct cam_lx7_core_info *core_info)
|
||||||
|
{
|
||||||
|
struct cam_icp_cpas_vote vote;
|
||||||
|
|
||||||
|
vote.ahb_vote.type = CAM_VOTE_ABSOLUTE;
|
||||||
|
vote.ahb_vote.vote.level = CAM_LOWSVS_VOTE;
|
||||||
|
vote.axi_vote.num_paths = 1;
|
||||||
|
|
||||||
|
vote.axi_vote.axi_path[0].path_data_type = CAM_ICP_DEFAULT_AXI_PATH;
|
||||||
|
vote.axi_vote.axi_path[0].transac_type = CAM_ICP_DEFAULT_AXI_TRANSAC;
|
||||||
|
vote.axi_vote.axi_path[0].camnoc_bw = CAM_ICP_BW_BYTES_VOTE;
|
||||||
|
vote.axi_vote.axi_path[0].mnoc_ab_bw = CAM_ICP_BW_BYTES_VOTE;
|
||||||
|
vote.axi_vote.axi_path[0].mnoc_ib_bw = CAM_ICP_BW_BYTES_VOTE;
|
||||||
|
vote.axi_vote.axi_path[0].ddr_ab_bw = CAM_ICP_BW_BYTES_VOTE;
|
||||||
|
vote.axi_vote.axi_path[0].ddr_ib_bw = CAM_ICP_BW_BYTES_VOTE;
|
||||||
|
|
||||||
|
return __lx7_cpas_start(core_info, &vote);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cam_lx7_cpas_stop(struct cam_lx7_core_info *core_info)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!core_info || !core_info->cpas_start)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
rc = cam_cpas_stop(core_info->cpas_handle);
|
||||||
|
if (rc) {
|
||||||
|
CAM_ERR(CAM_ICP, "failed to stop cpas rc=%d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
core_info->cpas_start = false;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cam_lx7_hw_init(void *priv, void *args, uint32_t arg_size)
|
||||||
|
{
|
||||||
|
struct cam_hw_info *lx7 = priv;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!lx7) {
|
||||||
|
CAM_ERR(CAM_ICP, "LX7 device info cannot be NULL");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cam_lx7_cpas_start(lx7->core_info);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = cam_lx7_soc_resources_enable(&lx7->soc_info);
|
||||||
|
if (rc) {
|
||||||
|
CAM_ERR(CAM_ICP, "failed to enable soc resources rc=%d", rc);
|
||||||
|
goto soc_fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
soc_fail:
|
||||||
|
cam_lx7_cpas_stop(lx7->core_info);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cam_lx7_hw_deinit(void *priv, void *args, uint32_t arg_size)
|
||||||
|
{
|
||||||
|
struct cam_hw_info *lx7_info = priv;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if (!lx7_info) {
|
||||||
|
CAM_ERR(CAM_ICP, "LX7 device info cannot be NULL");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = cam_lx7_soc_resources_disable(&lx7_info->soc_info);
|
||||||
|
if (rc) {
|
||||||
|
CAM_ERR(CAM_ICP, "failed to disable soc resources rc=%d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cam_lx7_cpas_stop(lx7_info->core_info);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int __tz_set_icp_state(uint32_t state)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = qcom_scm_set_remote_state(state, CAM_FW_PAS_ID);
|
||||||
|
if (rc)
|
||||||
|
CAM_ERR(CAM_ICP, "remote state set to %s failed rc=%d",
|
||||||
|
state == TZ_STATE_RESUME ? "resume" : "suspend", rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cam_lx7_process_cmd(void *priv, uint32_t cmd_type,
|
||||||
|
void *args, uint32_t arg_size)
|
||||||
|
{
|
||||||
|
struct cam_hw_info *lx7_info = priv;
|
||||||
|
int rc = -EINVAL;
|
||||||
|
|
||||||
|
if (!lx7_info) {
|
||||||
|
CAM_ERR(CAM_ICP, "LX7 device info cannot be NULL");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (cmd_type) {
|
||||||
|
case CAM_ICP_CMD_POWER_COLLAPSE:
|
||||||
|
rc = __tz_set_icp_state(TZ_STATE_SUSPEND);
|
||||||
|
break;
|
||||||
|
case CAM_ICP_CMD_POWER_RESUME:
|
||||||
|
rc = __tz_set_icp_state(TZ_STATE_RESUME);
|
||||||
|
break;
|
||||||
|
case CAM_ICP_CMD_VOTE_CPAS:
|
||||||
|
rc = cam_lx7_cpas_vote(lx7_info->core_info, args);
|
||||||
|
break;
|
||||||
|
case CAM_ICP_CMD_CPAS_START:
|
||||||
|
rc = __lx7_cpas_start(lx7_info->core_info, args);
|
||||||
|
break;
|
||||||
|
case CAM_ICP_CMD_CPAS_STOP:
|
||||||
|
rc = cam_lx7_cpas_stop(lx7_info->core_info);
|
||||||
|
break;
|
||||||
|
case CAM_ICP_CMD_UBWC_CFG:
|
||||||
|
rc = cam_lx7_ubwc_configure(&lx7_info->soc_info);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
CAM_ERR(CAM_ICP, "invalid command type=%u", cmd_type);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
irqreturn_t cam_lx7_handle_irq(int irq_num, void *data)
|
||||||
|
{
|
||||||
|
struct cam_hw_info *lx7_info = data;
|
||||||
|
struct cam_lx7_core_info *core_info = NULL;
|
||||||
|
bool recover = false;
|
||||||
|
uint32_t status = 0;
|
||||||
|
void __iomem *cirq_base;
|
||||||
|
|
||||||
|
if (!lx7_info) {
|
||||||
|
CAM_ERR(CAM_ICP, "invalid LX7 device info");
|
||||||
|
return IRQ_NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
cirq_base = lx7_info->soc_info.reg_map[LX7_CIRQ_BASE].mem_base;
|
||||||
|
|
||||||
|
status = cam_io_r_mb(cirq_base + ICP_LX7_CIRQ_OB_STATUS);
|
||||||
|
|
||||||
|
cam_io_w_mb(status, cirq_base + ICP_LX7_CIRQ_OB_CLEAR);
|
||||||
|
cam_io_w_mb(LX7_IRQ_CLEAR_CMD, cirq_base + ICP_LX7_CIRQ_OB_IRQ_CMD);
|
||||||
|
|
||||||
|
if (status & (LX7_WDT_BITE_WS0 | LX7_WDT_BITE_WS1)) {
|
||||||
|
CAM_ERR_RATE_LIMIT(CAM_ICP, "got watchdog interrupt from LX7");
|
||||||
|
recover = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
core_info = lx7_info->core_info;
|
||||||
|
|
||||||
|
spin_lock(&lx7_info->hw_lock);
|
||||||
|
if (core_info->irq_cb.cb)
|
||||||
|
core_info->irq_cb.cb(core_info->irq_cb.data,
|
||||||
|
recover);
|
||||||
|
spin_unlock(&lx7_info->hw_lock);
|
||||||
|
|
||||||
|
return IRQ_HANDLED;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cam_lx7_irq_raise(void *priv)
|
||||||
|
{
|
||||||
|
struct cam_hw_info *lx7_info = priv;
|
||||||
|
|
||||||
|
if (!lx7_info) {
|
||||||
|
CAM_ERR(CAM_ICP, "invalid LX7 device info");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cam_io_w_mb(LX7_HOST2ICPINT,
|
||||||
|
lx7_info->soc_info.reg_map[LX7_CIRQ_BASE].mem_base +
|
||||||
|
ICP_LX7_CIRQ_HOST2ICPINT);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cam_lx7_irq_enable(void *priv)
|
||||||
|
{
|
||||||
|
struct cam_hw_info *lx7_info = priv;
|
||||||
|
|
||||||
|
if (!lx7_info) {
|
||||||
|
CAM_ERR(CAM_ICP, "invalid LX7 device info");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
cam_io_w_mb(LX7_WDT_BITE_WS0 | LX7_ICP2HOSTINT,
|
||||||
|
lx7_info->soc_info.reg_map[LX7_CIRQ_BASE].mem_base +
|
||||||
|
ICP_LX7_CIRQ_OB_MASK);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __iomem *cam_lx7_iface_addr(void *priv)
|
||||||
|
{
|
||||||
|
struct cam_hw_info *lx7_info = priv;
|
||||||
|
void __iomem *base;
|
||||||
|
|
||||||
|
if (!lx7_info) {
|
||||||
|
CAM_ERR(CAM_ICP, "invalid LX7 device info");
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
base = lx7_info->soc_info.reg_map[LX7_CSR_BASE].mem_base;
|
||||||
|
|
||||||
|
return base + LX7_GEN_PURPOSE_REG_OFFSET;
|
||||||
|
}
|
39
drivers/cam_icp/icp_hw/lx7_hw/lx7_core.h
Normal file
39
drivers/cam_icp/icp_hw/lx7_hw/lx7_core.h
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, The Linux Foundation. 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 LX7_CSR_BASE 0
|
||||||
|
#define LX7_CIRQ_BASE 1
|
||||||
|
|
||||||
|
/* TODO: Update once we're ready to use TZ */
|
||||||
|
#define UNSUPPORTED_PROC_PAS_ID 30
|
||||||
|
#define CAM_FW_PAS_ID UNSUPPORTED_PROC_PAS_ID
|
||||||
|
|
||||||
|
struct cam_lx7_core_info {
|
||||||
|
struct cam_icp_irq_cb irq_cb;
|
||||||
|
uint32_t cpas_handle;
|
||||||
|
bool cpas_start;
|
||||||
|
};
|
||||||
|
|
||||||
|
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_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_ */
|
164
drivers/cam_icp/icp_hw/lx7_hw/lx7_dev.c
Normal file
164
drivers/cam_icp/icp_hw/lx7_hw/lx7_dev.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, The Linux Foundation. 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;
|
||||||
|
|
||||||
|
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");
|
12
drivers/cam_icp/icp_hw/lx7_hw/lx7_dev.h
Normal file
12
drivers/cam_icp/icp_hw/lx7_hw/lx7_dev.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
/* 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_ */
|
26
drivers/cam_icp/icp_hw/lx7_hw/lx7_reg.h
Normal file
26
drivers/cam_icp/icp_hw/lx7_hw/lx7_reg.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CAM_LX7_REG_H_
|
||||||
|
#define _CAM_LX7_REG_H_
|
||||||
|
|
||||||
|
#define ICP_LX7_CIRQ_OB_MASK 0x0
|
||||||
|
#define ICP_LX7_CIRQ_OB_CLEAR 0x4
|
||||||
|
#define ICP_LX7_CIRQ_OB_STATUS 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 ICP_LX7_CIRQ_HOST2ICPINT 0x124
|
||||||
|
#define LX7_HOST2ICPINT (1 << 0)
|
||||||
|
|
||||||
|
#endif /* _CAM_LX7_REG_H_ */
|
140
drivers/cam_icp/icp_hw/lx7_hw/lx7_soc.c
Normal file
140
drivers/cam_icp/icp_hw/lx7_hw/lx7_soc.c
Normal file
@@ -0,0 +1,140 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, The Linux Foundation. All rights reserved.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <linux/interrupt.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
|
||||||
|
#include "cam_debug_util.h"
|
||||||
|
#include "cam_soc_util.h"
|
||||||
|
#include "lx7_soc.h"
|
||||||
|
|
||||||
|
static int __ubwc_config_get(struct device_node *np, char *name, uint32_t *cfg)
|
||||||
|
{
|
||||||
|
int nconfig;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
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]",
|
||||||
|
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",
|
||||||
|
np, name, i);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cam_lx7_ubwc_config_get(struct lx7_soc_info *lx7_soc_info,
|
||||||
|
struct device_node *np)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = __ubwc_config_get(np, "ubwc-ipe-fetch-cfg",
|
||||||
|
lx7_soc_info->ubwc_cfg.ipe_fetch);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = __ubwc_config_get(np, "ubwc-ipe-write-cfg",
|
||||||
|
lx7_soc_info->ubwc_cfg.ipe_write);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = __ubwc_config_get(np, "ubwc-bps-fetch-cfg",
|
||||||
|
lx7_soc_info->ubwc_cfg.bps_fetch);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = __ubwc_config_get(np, "ubwc-bps-write-cfg",
|
||||||
|
lx7_soc_info->ubwc_cfg.bps_write);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cam_lx7_dt_properties_get(struct cam_hw_soc_info *soc_info)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (rc) {
|
||||||
|
CAM_ERR(CAM_ICP, "failed to get UBWC config props rc=%d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cam_lx7_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);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
rc = cam_soc_util_request_platform_resource(soc_info, handler, data);
|
||||||
|
if (rc) {
|
||||||
|
CAM_ERR(CAM_ICP,
|
||||||
|
"request for soc platform resource failed rc=%d", rc);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cam_lx7_soc_resources_deinit(struct cam_hw_soc_info *soc_info)
|
||||||
|
{
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
rc = cam_soc_util_release_platform_resource(soc_info);
|
||||||
|
if (rc)
|
||||||
|
CAM_ERR(CAM_ICP,
|
||||||
|
"release of soc platform resource failed rc=%d", rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cam_lx7_soc_resources_enable(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, "failed to enable soc resources rc=%d", rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cam_lx7_soc_resources_disable(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, "failed to disable soc resources rc=%d", rc);
|
||||||
|
|
||||||
|
return rc;
|
||||||
|
}
|
32
drivers/cam_icp/icp_hw/lx7_hw/lx7_soc.h
Normal file
32
drivers/cam_icp/icp_hw/lx7_hw/lx7_soc.h
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
/* 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 {
|
||||||
|
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);
|
||||||
|
|
||||||
|
#endif /* _CAM_LX7_SOC_H_ */
|
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-2.0-only
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2019-2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2019-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/build_bug.h>
|
#include <linux/build_bug.h>
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "a5_core.h"
|
#include "a5_core.h"
|
||||||
|
#include "lx7_dev.h"
|
||||||
#include "ipe_core.h"
|
#include "ipe_core.h"
|
||||||
#include "bps_core.h"
|
#include "bps_core.h"
|
||||||
#include "cam_icp_subdev.h"
|
#include "cam_icp_subdev.h"
|
||||||
@@ -118,6 +119,7 @@ static const struct camera_submodule_component camera_sensor[] = {
|
|||||||
static const struct camera_submodule_component camera_icp[] = {
|
static const struct camera_submodule_component camera_icp[] = {
|
||||||
#ifdef CONFIG_SPECTRA_ICP
|
#ifdef CONFIG_SPECTRA_ICP
|
||||||
{&cam_a5_init_module, &cam_a5_exit_module},
|
{&cam_a5_init_module, &cam_a5_exit_module},
|
||||||
|
{&cam_lx7_init_module, &cam_lx7_exit_module},
|
||||||
{&cam_ipe_init_module, &cam_ipe_exit_module},
|
{&cam_ipe_init_module, &cam_ipe_exit_module},
|
||||||
{&cam_bps_init_module, &cam_bps_exit_module},
|
{&cam_bps_init_module, &cam_bps_exit_module},
|
||||||
{&cam_icp_init_module, &cam_icp_exit_module},
|
{&cam_icp_init_module, &cam_icp_exit_module},
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
/* SPDX-License-Identifier: GPL-2.0-only */
|
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020, The Linux Foundation. All rights reserved.
|
* Copyright (c) 2020-2021, The Linux Foundation. All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef CAMERA_MAIN_H
|
#ifndef CAMERA_MAIN_H
|
||||||
@@ -44,6 +44,7 @@ extern struct platform_driver cam_flash_platform_driver;
|
|||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SPECTRA_ICP
|
#ifdef CONFIG_SPECTRA_ICP
|
||||||
extern struct platform_driver cam_a5_driver;
|
extern struct platform_driver cam_a5_driver;
|
||||||
|
extern struct platform_driver cam_lx7_driver;
|
||||||
extern struct platform_driver cam_ipe_driver;
|
extern struct platform_driver cam_ipe_driver;
|
||||||
extern struct platform_driver cam_bps_driver;
|
extern struct platform_driver cam_bps_driver;
|
||||||
extern struct platform_driver cam_icp_driver;
|
extern struct platform_driver cam_icp_driver;
|
||||||
@@ -112,6 +113,7 @@ static struct platform_driver *const cam_component_drivers[] = {
|
|||||||
#endif
|
#endif
|
||||||
#ifdef CONFIG_SPECTRA_ICP
|
#ifdef CONFIG_SPECTRA_ICP
|
||||||
&cam_a5_driver,
|
&cam_a5_driver,
|
||||||
|
&cam_lx7_driver,
|
||||||
&cam_ipe_driver,
|
&cam_ipe_driver,
|
||||||
&cam_bps_driver,
|
&cam_bps_driver,
|
||||||
&cam_icp_driver,
|
&cam_icp_driver,
|
||||||
|
Reference in New Issue
Block a user