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

Commit f54c9b19 authored by Pavan Kumar Chilamkurthi's avatar Pavan Kumar Chilamkurthi
Browse files

msm: camera: cpas: Enhance camnoc irq handling



Define data structures for different irq error data
and print the information in logs accordingly. Register
cpas callback from a5, vfe drivers to handle hw specific
camnoc ubwc errors.

Change-Id: I3c29b77a8aae9c2e14a459c35ac81de08c6659d3
Signed-off-by: default avatarPavan Kumar Chilamkurthi <pchilamk@codeaurora.org>
parent 064143a8
Loading
Loading
Loading
Loading
+8 −4
Original line number Diff line number Diff line
@@ -67,11 +67,15 @@ bool cam_cdm_set_cam_hw_version(
	return false;
}

void cam_cdm_cpas_cb(uint32_t client_handle, void *userdata,
	enum cam_camnoc_irq_type evt_type, uint32_t evt_data)
bool cam_cdm_cpas_cb(uint32_t client_handle, void *userdata,
	struct cam_cpas_irq_data *irq_data)
{
	CAM_ERR(CAM_CDM, "CPAS error callback type=%d with data=%x", evt_type,
		evt_data);
	if (!irq_data)
		return false;

	CAM_DBG(CAM_CDM, "CPAS error callback type=%d", irq_data->irq_type);

	return false;
}

struct cam_cdm_utils_ops *cam_cdm_get_ops(
+2 −2
Original line number Diff line number Diff line
@@ -32,8 +32,8 @@ int cam_cdm_process_cmd(void *hw_priv, uint32_t cmd, void *cmd_args,
	uint32_t arg_size);
bool cam_cdm_set_cam_hw_version(
	uint32_t ver, struct cam_hw_version *cam_version);
void cam_cdm_cpas_cb(uint32_t client_handle, void *userdata,
	enum cam_camnoc_irq_type evt_type, uint32_t evt_data);
bool cam_cdm_cpas_cb(uint32_t client_handle, void *userdata,
	struct cam_cpas_irq_data *irq_data);
struct cam_cdm_utils_ops *cam_cdm_get_ops(
	uint32_t ver, struct cam_hw_version *cam_version, bool by_cam_version);
int cam_virtual_cdm_submit_bl(struct cam_hw_info *cdm_hw,
+166 −81
Original line number Diff line number Diff line
@@ -24,6 +24,18 @@

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)
{
@@ -106,91 +118,155 @@ static int cam_cpastop_setup_regbase_indices(struct cam_hw_soc_info *soc_info,
}

static int cam_cpastop_handle_errlogger(struct cam_cpas *cpas_core,
	struct cam_hw_soc_info *soc_info)
	struct cam_hw_soc_info *soc_info,
	struct cam_camnoc_irq_slave_err_data *slave_err)
{
	uint32_t reg_value[4];
	int i;
	int size = camnoc_info->error_logger_size;
	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;
	}

	for (i = 0; (i + 3) < size; i = i + 4) {
		reg_value[0] = cam_io_r_mb(
	slave_err->mainctrl.value = cam_io_r_mb(
		soc_info->reg_map[camnoc_index].mem_base +
			camnoc_info->error_logger[i]);
		reg_value[1] = cam_io_r_mb(
		camnoc_info->err_logger->mainctrl);

	slave_err->errvld.value = cam_io_r_mb(
		soc_info->reg_map[camnoc_index].mem_base +
			camnoc_info->error_logger[i + 1]);
		reg_value[2] = cam_io_r_mb(
		camnoc_info->err_logger->errvld);

	slave_err->errlog0_low.value = cam_io_r_mb(
		soc_info->reg_map[camnoc_index].mem_base +
			camnoc_info->error_logger[i + 2]);
		reg_value[3] = cam_io_r_mb(
		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->error_logger[i + 3]);
		CAM_ERR(CAM_CPAS,
			"offset[0x%x] values [0x%x] [0x%x] [0x%x] [0x%x]",
			camnoc_info->error_logger[i], reg_value[0],
			reg_value[1], reg_value[2], reg_value[3]);
	}
		camnoc_info->err_logger->errlog0_high);

	if ((i + 2) < size) {
		reg_value[0] = cam_io_r_mb(
	slave_err->errlog1_low.value = cam_io_r_mb(
		soc_info->reg_map[camnoc_index].mem_base +
			camnoc_info->error_logger[i]);
		reg_value[1] = cam_io_r_mb(
		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->error_logger[i + 1]);
		reg_value[2] = cam_io_r_mb(
		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->error_logger[i + 2]);
		CAM_ERR(CAM_CPAS, "offset[0x%x] values [0x%x] [0x%x] [0x%x]",
			camnoc_info->error_logger[i], reg_value[0],
			reg_value[1], reg_value[2]);
		i = i + 3;
	}
		camnoc_info->err_logger->errlog2_low);

	if ((i + 1) < size) {
		reg_value[0] = cam_io_r_mb(
	slave_err->errlog2_high.value = cam_io_r_mb(
		soc_info->reg_map[camnoc_index].mem_base +
			camnoc_info->error_logger[i]);
		reg_value[1] = cam_io_r_mb(
		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->error_logger[i + 1]);
		CAM_ERR(CAM_CPAS, "offset[0x%x] values [0x%x] [0x%x]",
			camnoc_info->error_logger[i], reg_value[0],
			reg_value[1]);
		i = i + 2;
	}
		camnoc_info->err_logger->errlog3_low);

	if (i < size) {
		reg_value[0] = cam_io_r_mb(
	slave_err->errlog3_high.value = cam_io_r_mb(
		soc_info->reg_map[camnoc_index].mem_base +
			camnoc_info->error_logger[i]);
		CAM_ERR(CAM_CPAS, "offset[0x%x] values [0x%x]",
			camnoc_info->error_logger[i], reg_value[0]);
		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_err(struct cam_cpas *cpas_core,
	struct cam_hw_soc_info *soc_info, int i)
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)
{
	uint32_t reg_value;
	int camnoc_index = cpas_core->regbase_index[CAM_CPAS_REG_CAMNOC];

	reg_value = cam_io_r_mb(soc_info->reg_map[camnoc_index].mem_base +
	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);

	CAM_ERR(CAM_CPAS,
		"Dumping ubwc error status [%d]: offset[0x%x] value[0x%x]",
		i, camnoc_info->irq_err[i].err_status.offset, reg_value);
	/* 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 reg_value;
	return 0;
}

static int cam_cpastop_handle_ahb_timeout_err(struct cam_hw_info *cpas_hw)
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(CAM_CPAS, "ahb timout error");
	CAM_ERR_RATE_LIMIT(CAM_CPAS, "ahb timout error");

	return 0;
}
@@ -228,10 +304,11 @@ static int cam_cpastop_reset_irq(struct cam_hw_info *cpas_hw)
}

static void cam_cpastop_notify_clients(struct cam_cpas *cpas_core,
	enum cam_camnoc_hw_irq_type irq_type, uint32_t irq_data)
	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",
@@ -243,13 +320,15 @@ static void cam_cpastop_notify_clients(struct cam_cpas *cpas_core,
			cpas_client = cpas_core->cpas_client[i];
			if (cpas_client->data.cam_cpas_client_cb) {
				CAM_DBG(CAM_CPAS,
					"Calling client CB %d : %d 0x%x",
					i, irq_type, irq_data);
					"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,
					(enum cam_camnoc_irq_type)irq_type,
					irq_data);
				if (error_handled)
					break;
			}
		}
	}
@@ -263,7 +342,7 @@ static void cam_cpastop_work(struct work_struct *work)
	struct cam_hw_soc_info *soc_info;
	int i;
	enum cam_camnoc_hw_irq_type irq_type;
	uint32_t irq_data;
	struct cam_cpas_irq_data irq_data;

	payload = container_of(work, struct cam_cpas_work_payload, work);
	if (!payload) {
@@ -280,23 +359,30 @@ static void cam_cpastop_work(struct work_struct *work)
			(camnoc_info->irq_err[i].enable)) {
			irq_type = camnoc_info->irq_err[i].irq_type;
			CAM_ERR(CAM_CPAS, "Error occurred, type=%d", irq_type);
			irq_data = 0;
			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:
				irq_data = cam_cpastop_handle_errlogger(
					cpas_core, soc_info);
				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_DECODE_ERROR:
			case CAM_CAMNOC_HW_IRQ_IPE_BPS_UBWC_ENCODE_ERROR:
				irq_data = cam_cpastop_handle_ubwc_err(
					cpas_core, soc_info, i);
				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:
				irq_data = cam_cpastop_handle_ahb_timeout_err(
					cpas_hw);
				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");
@@ -306,8 +392,7 @@ static void cam_cpastop_work(struct work_struct *work)
				break;
			}

			cam_cpastop_notify_clients(cpas_core, irq_type,
				irq_data);
			cam_cpastop_notify_clients(cpas_core, &irq_data);

			payload->irq_status &=
				~camnoc_info->irq_err[i].sbm_port;
+30 −4
Original line number Diff line number Diff line
@@ -172,6 +172,34 @@ struct cam_cpas_hw_errata_wa_list {
	struct cam_cpas_hw_errata_wa camnoc_flush_slave_pending_trans;
};

/**
 * struct cam_camnoc_err_logger_info : CAMNOC error logger register offsets
 *
 * @mainctrl: Register offset for mainctrl
 * @errvld: Register offset for errvld
 * @errlog0_low: Register offset for errlog0_low
 * @errlog0_high: Register offset for errlog0_high
 * @errlog1_low: Register offset for errlog1_low
 * @errlog1_high: Register offset for errlog1_high
 * @errlog2_low: Register offset for errlog2_low
 * @errlog2_high: Register offset for errlog2_high
 * @errlog3_low: Register offset for errlog3_low
 * @errlog3_high: Register offset for errlog3_high
 *
 */
struct cam_camnoc_err_logger_info {
	uint32_t mainctrl;
	uint32_t errvld;
	uint32_t errlog0_low;
	uint32_t errlog0_high;
	uint32_t errlog1_low;
	uint32_t errlog1_high;
	uint32_t errlog2_low;
	uint32_t errlog2_high;
	uint32_t errlog3_low;
	uint32_t errlog3_high;
};

/**
 * struct cam_camnoc_info : Overall CAMNOC settings info
 *
@@ -180,8 +208,7 @@ struct cam_cpas_hw_errata_wa_list {
 * @irq_sbm: Pointer to CAMNOC IRQ SBM settings
 * @irq_err: Pointer to CAMNOC IRQ Error settings
 * @irq_err_size: Array size of IRQ Error settings
 * @error_logger: Pointer to CAMNOC IRQ Error logger read registers
 * @error_logger_size: Array size of IRQ Error logger
 * @err_logger: Pointer to CAMNOC IRQ Error logger read registers
 * @errata_wa_list: HW Errata workaround info
 *
 */
@@ -191,8 +218,7 @@ struct cam_camnoc_info {
	struct cam_camnoc_irq_sbm *irq_sbm;
	struct cam_camnoc_irq_err *irq_err;
	int irq_err_size;
	uint32_t *error_logger;
	int error_logger_size;
	struct cam_camnoc_err_logger_info *err_logger;
	struct cam_cpas_hw_errata_wa_list *errata_wa_list;
};

+12 −16
Original line number Diff line number Diff line
@@ -498,19 +498,17 @@ static struct cam_camnoc_specific
	}
};

uint32_t slave_error_logger[] = {
	0x2700, /* ERRLOGGER_SWID_LOW */
	0x2704, /* ERRLOGGER_SWID_HIGH */
	0x2708, /* ERRLOGGER_MAINCTL_LOW */
	0x2710, /* ERRLOGGER_ERRVLD_LOW */
	0x2720, /* ERRLOGGER_ERRLOG0_LOW */
	0x2724, /* ERRLOGGER_ERRLOG0_HIGH */
	0x2728, /* ERRLOGGER_ERRLOG1_LOW */
	0x272c, /* ERRLOGGER_ERRLOG1_HIGH */
	0x2730, /* ERRLOGGER_ERRLOG2_LOW */
	0x2734, /* ERRLOGGER_ERRLOG2_HIGH */
	0x2738, /* ERRLOGGER_ERRLOG3_LOW */
	0x273c, /* ERRLOGGER_ERRLOG3_HIGH */
static struct cam_camnoc_err_logger_info cam170_cpas100_err_logger_offsets = {
	.mainctrl     =  0x2708, /* ERRLOGGER_MAINCTL_LOW */
	.errvld       =  0x2710, /* ERRLOGGER_ERRVLD_LOW */
	.errlog0_low  =  0x2720, /* ERRLOGGER_ERRLOG0_LOW */
	.errlog0_high =  0x2724, /* ERRLOGGER_ERRLOG0_HIGH */
	.errlog1_low  =  0x2728, /* ERRLOGGER_ERRLOG1_LOW */
	.errlog1_high =  0x272c, /* ERRLOGGER_ERRLOG1_HIGH */
	.errlog2_low  =  0x2730, /* ERRLOGGER_ERRLOG2_LOW */
	.errlog2_high =  0x2734, /* ERRLOGGER_ERRLOG2_HIGH */
	.errlog3_low  =  0x2738, /* ERRLOGGER_ERRLOG3_LOW */
	.errlog3_high =  0x273c, /* ERRLOGGER_ERRLOG3_HIGH */
};

static struct cam_cpas_hw_errata_wa_list cam170_cpas100_errata_wa_list = {
@@ -533,9 +531,7 @@ struct cam_camnoc_info cam170_cpas100_camnoc_info = {
	.irq_err = &cam_cpas100_irq_err[0],
	.irq_err_size = sizeof(cam_cpas100_irq_err) /
		sizeof(cam_cpas100_irq_err[0]),
	.error_logger = &slave_error_logger[0],
	.error_logger_size = sizeof(slave_error_logger) /
		sizeof(slave_error_logger[0]),
	.err_logger = &cam170_cpas100_err_logger_offsets,
	.errata_wa_list = &cam170_cpas100_errata_wa_list,
};

Loading