blob: 719fb12d7353279162faa2cdb52fa5686c21174a [file] [log] [blame]
/* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
* only version 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/slab.h>
#include "cam_cpas_hw_intf.h"
#include "cam_cpas_hw.h"
#include "cam_cpastop_hw.h"
#include "cam_io_util.h"
#include "cam_cpas_soc.h"
#include "cpastop100.h"
#include "cpastop_v150_100.h"
#include "cpastop_v170_110.h"
#include "cpastop_v175_100.h"
#include "cpastop_v175_101.h"
#include "cpastop_v175_120.h"
struct cam_camnoc_info *camnoc_info;
#define CAMNOC_SLAVE_MAX_ERR_CODE 7
static const char * const camnoc_salve_err_code[] = {
"Target Error", /* err code 0 */
"Address decode error", /* err code 1 */
"Unsupported request", /* err code 2 */
"Disconnected target", /* err code 3 */
"Security violation", /* err code 4 */
"Hidden security violation", /* err code 5 */
"Timeout Error", /* err code 6 */
"Unknown Error", /* unknown err code */
};
static int cam_cpastop_get_hw_info(struct cam_hw_info *cpas_hw,
struct cam_cpas_hw_caps *hw_caps)
{
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
int32_t reg_indx = cpas_core->regbase_index[CAM_CPAS_REG_CPASTOP];
uint32_t reg_value;
if (reg_indx == -1)
return -EINVAL;
hw_caps->camera_family = CAM_FAMILY_CPAS_SS;
reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x0);
hw_caps->camera_version.major =
CAM_BITS_MASK_SHIFT(reg_value, 0xff0000, 0x10);
hw_caps->camera_version.minor =
CAM_BITS_MASK_SHIFT(reg_value, 0xff00, 0x8);
hw_caps->camera_version.incr =
CAM_BITS_MASK_SHIFT(reg_value, 0xff, 0x0);
reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x4);
hw_caps->cpas_version.major =
CAM_BITS_MASK_SHIFT(reg_value, 0xf0000000, 0x1c);
hw_caps->cpas_version.minor =
CAM_BITS_MASK_SHIFT(reg_value, 0xfff0000, 0x10);
hw_caps->cpas_version.incr =
CAM_BITS_MASK_SHIFT(reg_value, 0xffff, 0x0);
reg_value = cam_io_r_mb(soc_info->reg_map[reg_indx].mem_base + 0x8);
hw_caps->camera_capability = reg_value;
CAM_DBG(CAM_FD, "Family %d, version %d.%d.%d, cpas %d.%d.%d, cap 0x%x",
hw_caps->camera_family, hw_caps->camera_version.major,
hw_caps->camera_version.minor, hw_caps->camera_version.incr,
hw_caps->cpas_version.major, hw_caps->cpas_version.minor,
hw_caps->cpas_version.incr, hw_caps->camera_capability);
soc_info->hw_version = CAM_CPAS_TITAN_NONE;
if ((hw_caps->camera_version.major == 1) &&
(hw_caps->camera_version.minor == 7) &&
(hw_caps->camera_version.incr == 0)) {
if ((hw_caps->cpas_version.major == 1) &&
(hw_caps->cpas_version.minor == 0) &&
(hw_caps->cpas_version.incr == 0))
soc_info->hw_version = CAM_CPAS_TITAN_170_V100;
else if ((hw_caps->cpas_version.major == 1) &&
(hw_caps->cpas_version.minor == 1) &&
(hw_caps->cpas_version.incr == 0))
soc_info->hw_version = CAM_CPAS_TITAN_170_V110;
else if ((hw_caps->cpas_version.major == 1) &&
(hw_caps->cpas_version.minor == 2) &&
(hw_caps->cpas_version.incr == 0))
soc_info->hw_version = CAM_CPAS_TITAN_170_V120;
} else if ((hw_caps->camera_version.major == 1) &&
(hw_caps->camera_version.minor == 7) &&
(hw_caps->camera_version.incr == 5)) {
if ((hw_caps->cpas_version.major == 1) &&
(hw_caps->cpas_version.minor == 0) &&
(hw_caps->cpas_version.incr == 0))
soc_info->hw_version = CAM_CPAS_TITAN_175_V100;
else if ((hw_caps->cpas_version.major == 1) &&
(hw_caps->cpas_version.minor == 0) &&
(hw_caps->cpas_version.incr == 1))
soc_info->hw_version = CAM_CPAS_TITAN_175_V101;
else if ((hw_caps->cpas_version.major == 1) &&
(hw_caps->cpas_version.minor == 2) &&
(hw_caps->cpas_version.incr == 0))
soc_info->hw_version = CAM_CPAS_TITAN_175_V120;
} else if ((hw_caps->camera_version.major == 1) &&
(hw_caps->camera_version.minor == 5) &&
(hw_caps->camera_version.incr == 0)) {
if ((hw_caps->cpas_version.major == 1) &&
(hw_caps->cpas_version.minor == 0) &&
(hw_caps->cpas_version.incr == 0))
soc_info->hw_version = CAM_CPAS_TITAN_150_V100;
}
CAM_DBG(CAM_CPAS, "CPAS HW VERSION %x", soc_info->hw_version);
return 0;
}
static int cam_cpastop_setup_regbase_indices(struct cam_hw_soc_info *soc_info,
int32_t regbase_index[], int32_t num_reg_map)
{
uint32_t index;
int rc;
if (num_reg_map > CAM_CPAS_REG_MAX) {
CAM_ERR(CAM_CPAS, "invalid num_reg_map=%d", num_reg_map);
return -EINVAL;
}
if (soc_info->num_mem_block > CAM_SOC_MAX_BLOCK) {
CAM_ERR(CAM_CPAS, "invalid num_mem_block=%d",
soc_info->num_mem_block);
return -EINVAL;
}
rc = cam_common_util_get_string_index(soc_info->mem_block_name,
soc_info->num_mem_block, "cam_cpas_top", &index);
if ((rc == 0) && (index < num_reg_map)) {
regbase_index[CAM_CPAS_REG_CPASTOP] = index;
} else {
CAM_ERR(CAM_CPAS, "regbase not found for CPASTOP, rc=%d, %d %d",
rc, index, num_reg_map);
return -EINVAL;
}
rc = cam_common_util_get_string_index(soc_info->mem_block_name,
soc_info->num_mem_block, "cam_camnoc", &index);
if ((rc == 0) && (index < num_reg_map)) {
regbase_index[CAM_CPAS_REG_CAMNOC] = index;
} else {
CAM_ERR(CAM_CPAS, "regbase not found for CAMNOC, rc=%d, %d %d",
rc, index, num_reg_map);
return -EINVAL;
}
rc = cam_common_util_get_string_index(soc_info->mem_block_name,
soc_info->num_mem_block, "core_top_csr_tcsr", &index);
if ((rc == 0) && (index < num_reg_map)) {
regbase_index[CAM_CPAS_REG_CSR_TCSR] = index;
} else {
CAM_DBG(CAM_CPAS, "regbase not found for CAMNOC, rc=%d, %d %d",
rc, index, num_reg_map);
}
return 0;
}
static int cam_cpastop_handle_errlogger(struct cam_cpas *cpas_core,
struct cam_hw_soc_info *soc_info,
struct cam_camnoc_irq_slave_err_data *slave_err)
{
int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
int err_code_index = 0;
if (!camnoc_info->err_logger) {
CAM_ERR_RATE_LIMIT(CAM_CPAS, "Invalid err logger info");
return -EINVAL;
}
slave_err->mainctrl.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->mainctrl);
slave_err->errvld.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->errvld);
slave_err->errlog0_low.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->errlog0_low);
slave_err->errlog0_high.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->errlog0_high);
slave_err->errlog1_low.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->errlog1_low);
slave_err->errlog1_high.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->errlog1_high);
slave_err->errlog2_low.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->errlog2_low);
slave_err->errlog2_high.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->errlog2_high);
slave_err->errlog3_low.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->errlog3_low);
slave_err->errlog3_high.value = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->err_logger->errlog3_high);
CAM_ERR_RATE_LIMIT(CAM_CPAS,
"Possible memory configuration issue, fault at SMMU raised as CAMNOC SLAVE_IRQ");
CAM_ERR_RATE_LIMIT(CAM_CPAS,
"mainctrl[0x%x 0x%x] errvld[0x%x 0x%x] stall_en=%d, fault_en=%d, err_vld=%d",
camnoc_info->err_logger->mainctrl,
slave_err->mainctrl.value,
camnoc_info->err_logger->errvld,
slave_err->errvld.value,
slave_err->mainctrl.stall_en,
slave_err->mainctrl.fault_en,
slave_err->errvld.err_vld);
err_code_index = slave_err->errlog0_low.err_code;
if (err_code_index > CAMNOC_SLAVE_MAX_ERR_CODE)
err_code_index = CAMNOC_SLAVE_MAX_ERR_CODE;
CAM_ERR_RATE_LIMIT(CAM_CPAS,
"errlog0 low[0x%x 0x%x] high[0x%x 0x%x] loginfo_vld=%d, word_error=%d, non_secure=%d, device=%d, opc=%d, err_code=%d(%s) sizef=%d, addr_space=%d, len1=%d",
camnoc_info->err_logger->errlog0_low,
slave_err->errlog0_low.value,
camnoc_info->err_logger->errlog0_high,
slave_err->errlog0_high.value,
slave_err->errlog0_low.loginfo_vld,
slave_err->errlog0_low.word_error,
slave_err->errlog0_low.non_secure,
slave_err->errlog0_low.device,
slave_err->errlog0_low.opc,
slave_err->errlog0_low.err_code,
camnoc_salve_err_code[err_code_index],
slave_err->errlog0_low.sizef,
slave_err->errlog0_low.addr_space,
slave_err->errlog0_high.len1);
CAM_ERR_RATE_LIMIT(CAM_CPAS,
"errlog1_low[0x%x 0x%x] errlog1_high[0x%x 0x%x] errlog2_low[0x%x 0x%x] errlog2_high[0x%x 0x%x] errlog3_low[0x%x 0x%x] errlog3_high[0x%x 0x%x]",
camnoc_info->err_logger->errlog1_low,
slave_err->errlog1_low.value,
camnoc_info->err_logger->errlog1_high,
slave_err->errlog1_high.value,
camnoc_info->err_logger->errlog2_low,
slave_err->errlog2_low.value,
camnoc_info->err_logger->errlog2_high,
slave_err->errlog2_high.value,
camnoc_info->err_logger->errlog3_low,
slave_err->errlog3_low.value,
camnoc_info->err_logger->errlog3_high,
slave_err->errlog3_high.value);
return 0;
}
static int cam_cpastop_handle_ubwc_enc_err(struct cam_cpas *cpas_core,
struct cam_hw_soc_info *soc_info, int i,
struct cam_camnoc_irq_ubwc_enc_data *enc_err)
{
int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
enc_err->encerr_status.value =
cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->irq_err[i].err_status.offset);
/* Let clients handle the UBWC errors */
CAM_DBG(CAM_CPAS,
"ubwc enc err [%d]: offset[0x%x] value[0x%x]",
i, camnoc_info->irq_err[i].err_status.offset,
enc_err->encerr_status.value);
return 0;
}
static int cam_cpastop_handle_ubwc_dec_err(struct cam_cpas *cpas_core,
struct cam_hw_soc_info *soc_info, int i,
struct cam_camnoc_irq_ubwc_dec_data *dec_err)
{
int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
dec_err->decerr_status.value =
cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->irq_err[i].err_status.offset);
/* Let clients handle the UBWC errors */
CAM_DBG(CAM_CPAS,
"ubwc dec err status [%d]: offset[0x%x] value[0x%x] thr_err=%d, fcl_err=%d, len_md_err=%d, format_err=%d",
i, camnoc_info->irq_err[i].err_status.offset,
dec_err->decerr_status.value,
dec_err->decerr_status.thr_err,
dec_err->decerr_status.fcl_err,
dec_err->decerr_status.len_md_err,
dec_err->decerr_status.format_err);
return 0;
}
static int cam_cpastop_handle_ahb_timeout_err(struct cam_hw_info *cpas_hw,
struct cam_camnoc_irq_ahb_timeout_data *ahb_err)
{
CAM_ERR_RATE_LIMIT(CAM_CPAS, "ahb timeout error");
return 0;
}
static int cam_cpastop_disable_test_irq(struct cam_hw_info *cpas_hw)
{
camnoc_info->irq_sbm->sbm_clear.value &= ~0x4;
camnoc_info->irq_sbm->sbm_enable.value &= ~0x100;
camnoc_info->irq_err[CAM_CAMNOC_HW_IRQ_CAMNOC_TEST].enable = false;
return 0;
}
static int cam_cpastop_reset_irq(struct cam_hw_info *cpas_hw)
{
int i;
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->irq_sbm->sbm_clear);
for (i = 0; i < camnoc_info->irq_err_size; i++) {
if (camnoc_info->irq_err[i].enable)
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->irq_err[i].err_clear);
}
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->irq_sbm->sbm_enable);
for (i = 0; i < camnoc_info->irq_err_size; i++) {
if (camnoc_info->irq_err[i].enable)
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->irq_err[i].err_enable);
}
return 0;
}
static void cam_cpastop_notify_clients(struct cam_cpas *cpas_core,
struct cam_cpas_irq_data *irq_data)
{
int i;
struct cam_cpas_client *cpas_client;
bool error_handled = false;
CAM_DBG(CAM_CPAS,
"Notify CB : num_clients=%d, registered=%d, started=%d",
cpas_core->num_clients, cpas_core->registered_clients,
cpas_core->streamon_clients);
for (i = 0; i < cpas_core->num_clients; i++) {
if (CAM_CPAS_CLIENT_STARTED(cpas_core, i)) {
cpas_client = cpas_core->cpas_client[i];
if (cpas_client->data.cam_cpas_client_cb) {
CAM_DBG(CAM_CPAS,
"Calling client CB %d : %d",
i, irq_data->irq_type);
error_handled =
cpas_client->data.cam_cpas_client_cb(
cpas_client->data.client_handle,
cpas_client->data.userdata,
irq_data);
if (error_handled)
break;
}
}
}
}
static void cam_cpastop_work(struct work_struct *work)
{
struct cam_cpas_work_payload *payload;
struct cam_hw_info *cpas_hw;
struct cam_cpas *cpas_core;
struct cam_hw_soc_info *soc_info;
int i;
enum cam_camnoc_hw_irq_type irq_type;
struct cam_cpas_irq_data irq_data;
payload = container_of(work, struct cam_cpas_work_payload, work);
if (!payload) {
CAM_ERR(CAM_CPAS, "NULL payload");
return;
}
cpas_hw = payload->hw;
cpas_core = (struct cam_cpas *) cpas_hw->core_info;
soc_info = &cpas_hw->soc_info;
if (!atomic_inc_not_zero(&cpas_core->irq_count)) {
CAM_ERR(CAM_CPAS, "CPAS off");
return;
}
mutex_lock(&cpas_hw->hw_mutex);
if (cpas_hw->hw_state == CAM_HW_STATE_POWER_DOWN) {
CAM_ERR(CAM_CPAS, "CPAS CORE is off");
mutex_unlock(&cpas_hw->hw_mutex);
return;
}
for (i = 0; i < camnoc_info->irq_err_size; i++) {
if ((payload->irq_status & camnoc_info->irq_err[i].sbm_port) &&
(camnoc_info->irq_err[i].enable)) {
irq_type = camnoc_info->irq_err[i].irq_type;
CAM_ERR_RATE_LIMIT(CAM_CPAS,
"Error occurred, type=%d", irq_type);
memset(&irq_data, 0x0, sizeof(irq_data));
irq_data.irq_type = (enum cam_camnoc_irq_type)irq_type;
switch (irq_type) {
case CAM_CAMNOC_HW_IRQ_SLAVE_ERROR:
cam_cpastop_handle_errlogger(
cpas_core, soc_info,
&irq_data.u.slave_err);
break;
case CAM_CAMNOC_HW_IRQ_IFE02_UBWC_ENCODE_ERROR:
case CAM_CAMNOC_HW_IRQ_IFE13_UBWC_ENCODE_ERROR:
case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR:
cam_cpastop_handle_ubwc_enc_err(
cpas_core, soc_info, i,
&irq_data.u.enc_err);
break;
case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_DECODE_ERROR:
cam_cpastop_handle_ubwc_dec_err(
cpas_core, soc_info, i,
&irq_data.u.dec_err);
break;
case CAM_CAMNOC_HW_IRQ_AHB_TIMEOUT:
cam_cpastop_handle_ahb_timeout_err(
cpas_hw, &irq_data.u.ahb_err);
break;
case CAM_CAMNOC_HW_IRQ_CAMNOC_TEST:
CAM_DBG(CAM_CPAS, "TEST IRQ");
break;
default:
CAM_ERR(CAM_CPAS, "Invalid IRQ type");
break;
}
cam_cpastop_notify_clients(cpas_core, &irq_data);
payload->irq_status &=
~camnoc_info->irq_err[i].sbm_port;
}
}
mutex_unlock(&cpas_hw->hw_mutex);
atomic_dec(&cpas_core->irq_count);
wake_up(&cpas_core->irq_count_wq);
CAM_DBG(CAM_CPAS, "irq_count=%d\n", atomic_read(&cpas_core->irq_count));
if (payload->irq_status)
CAM_ERR(CAM_CPAS, "IRQ not handled irq_status=0x%x",
payload->irq_status);
kfree(payload);
}
static irqreturn_t cam_cpastop_handle_irq(int irq_num, void *data)
{
struct cam_hw_info *cpas_hw = (struct cam_hw_info *)data;
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
struct cam_cpas_work_payload *payload;
if (!atomic_inc_not_zero(&cpas_core->irq_count)) {
CAM_ERR(CAM_CPAS, "CPAS off");
return IRQ_HANDLED;
}
payload = kzalloc(sizeof(struct cam_cpas_work_payload), GFP_ATOMIC);
if (!payload)
goto done;
payload->irq_status = cam_io_r_mb(
soc_info->reg_map[camnoc_index].mem_base +
camnoc_info->irq_sbm->sbm_status.offset);
CAM_DBG(CAM_CPAS, "IRQ callback, irq_status=0x%x", payload->irq_status);
payload->hw = cpas_hw;
INIT_WORK((struct work_struct *)&payload->work, cam_cpastop_work);
if (TEST_IRQ_ENABLE)
cam_cpastop_disable_test_irq(cpas_hw);
cam_cpastop_reset_irq(cpas_hw);
queue_work(cpas_core->work_queue, &payload->work);
done:
atomic_dec(&cpas_core->irq_count);
wake_up(&cpas_core->irq_count_wq);
return IRQ_HANDLED;
}
static int cam_cpastop_poweron(struct cam_hw_info *cpas_hw)
{
int i;
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
struct cam_cpas_private_soc *soc_private = soc_info->soc_private;
cam_cpastop_reset_irq(cpas_hw);
for (i = 0; i < camnoc_info->specific_size; i++) {
if (camnoc_info->specific[i].enable) {
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->specific[i].priority_lut_low);
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->specific[i].priority_lut_high);
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->specific[i].urgency);
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->specific[i].danger_lut);
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->specific[i].safe_lut);
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->specific[i].ubwc_ctl);
cam_cpas_util_reg_update(cpas_hw, CAM_CPAS_REG_CAMNOC,
&camnoc_info->specific[i].flag_out_set0_low);
}
}
if (soc_private && ((soc_private->soc_id == SDM710_SOC_ID) ||
(soc_private->soc_id == SDM712_SOC_ID) ||
((soc_private->soc_id == SDM670_SOC_ID) &&
(soc_private->hw_rev == SDM670_V1_1)))) {
struct cam_cpas_reg *reg_info;
int tcsr_index;
void __iomem *mem_base;
reg_info = &camnoc_info->errata_wa_list->tcsr_reg.
tcsr_conn_box_spare_0;
tcsr_index = cpas_core->regbase_index[CAM_CPAS_REG_CSR_TCSR];
if (tcsr_index == -1) {
CAM_DBG(CAM_CPAS, "index in not initialized");
return 0;
}
mem_base = soc_info->reg_map[tcsr_index].mem_base;
reg_info->value = TCSR_CONN_SET;
cam_io_w_mb(reg_info->value, mem_base + reg_info->offset);
CAM_DBG(CAM_CPAS, "tcsr(0x%lx) value %d",
(unsigned long int)mem_base + reg_info->offset,
cam_io_r_mb(mem_base + reg_info->offset));
}
return 0;
}
static int cam_cpastop_poweroff(struct cam_hw_info *cpas_hw)
{
struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];
int rc = 0;
struct cam_cpas_hw_errata_wa_list *errata_wa_list =
camnoc_info->errata_wa_list;
struct cam_cpas_private_soc *soc_private =
cpas_hw->soc_info.soc_private;
if (!errata_wa_list)
return 0;
if (errata_wa_list->camnoc_flush_slave_pending_trans.enable) {
struct cam_cpas_hw_errata_wa *errata_wa =
&errata_wa_list->camnoc_flush_slave_pending_trans;
rc = cam_io_poll_value_wmask(
soc_info->reg_map[camnoc_index].mem_base +
errata_wa->data.reg_info.offset,
errata_wa->data.reg_info.value,
errata_wa->data.reg_info.mask,
CAM_CPAS_POLL_RETRY_CNT,
CAM_CPAS_POLL_MIN_USECS, CAM_CPAS_POLL_MAX_USECS);
if (rc) {
CAM_DBG(CAM_CPAS,
"camnoc flush slave pending trans failed");
/* Do not return error, passthrough */
rc = 0;
}
}
if (soc_private && ((soc_private->soc_id == SDM710_SOC_ID)
|| (soc_private->soc_id == SDM712_SOC_ID)
|| ((soc_private->soc_id == SDM670_SOC_ID) &&
(soc_private->hw_rev == SDM670_V1_1)))) {
struct cam_cpas_reg *reg_info;
int tcsr_index;
void __iomem *mem_base;
reg_info = &camnoc_info->errata_wa_list->tcsr_reg.
tcsr_conn_box_spare_0;
reg_info->value = TCSR_CONN_RESET;
tcsr_index = cpas_core->regbase_index[CAM_CPAS_REG_CSR_TCSR];
if (tcsr_index == -1) {
CAM_DBG(CAM_CPAS, "index in not initialized");
return 0;
}
mem_base = soc_info->reg_map[tcsr_index].mem_base;
cam_io_w_mb(reg_info->value, mem_base + reg_info->offset);
CAM_DBG(CAM_CPAS, "tcsr(0x%lx) value %d",
(unsigned long int)mem_base + reg_info->offset,
cam_io_r_mb(mem_base + reg_info->offset));
}
return rc;
}
static int cam_cpastop_init_hw_version(struct cam_hw_info *cpas_hw,
struct cam_cpas_hw_caps *hw_caps)
{
int rc = 0;
struct cam_hw_soc_info *soc_info = &cpas_hw->soc_info;
CAM_DBG(CAM_CPAS,
"hw_version=0x%x Camera Version %d.%d.%d, cpas version %d.%d.%d",
soc_info->hw_version,
hw_caps->camera_version.major,
hw_caps->camera_version.minor,
hw_caps->camera_version.incr,
hw_caps->cpas_version.major,
hw_caps->cpas_version.minor,
hw_caps->cpas_version.incr);
switch (soc_info->hw_version) {
case CAM_CPAS_TITAN_170_V100:
camnoc_info = &cam170_cpas100_camnoc_info;
break;
case CAM_CPAS_TITAN_170_V110:
camnoc_info = &cam170_cpas110_camnoc_info;
break;
case CAM_CPAS_TITAN_175_V100:
camnoc_info = &cam175_cpas100_camnoc_info;
break;
case CAM_CPAS_TITAN_175_V101:
camnoc_info = &cam175_cpas101_camnoc_info;
break;
case CAM_CPAS_TITAN_175_V120:
camnoc_info = &cam175_cpas120_camnoc_info;
break;
case CAM_CPAS_TITAN_150_V100:
camnoc_info = &cam150_cpas100_camnoc_info;
break;
default:
CAM_ERR(CAM_CPAS, "Camera Version not supported %d.%d.%d",
hw_caps->camera_version.major,
hw_caps->camera_version.minor,
hw_caps->camera_version.incr);
rc = -EINVAL;
break;
}
return 0;
}
int cam_cpastop_get_internal_ops(struct cam_cpas_internal_ops *internal_ops)
{
if (!internal_ops) {
CAM_ERR(CAM_CPAS, "invalid NULL param");
return -EINVAL;
}
internal_ops->get_hw_info = cam_cpastop_get_hw_info;
internal_ops->init_hw_version = cam_cpastop_init_hw_version;
internal_ops->handle_irq = cam_cpastop_handle_irq;
internal_ops->setup_regbase = cam_cpastop_setup_regbase_indices;
internal_ops->power_on = cam_cpastop_poweron;
internal_ops->power_off = cam_cpastop_poweroff;
return 0;
}