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

Commit ef63d3df authored by Alok Pandey's avatar Alok Pandey Committed by Gerrit - the friendly Code Review server
Browse files

msm: camera: icp: Handle Watchdog/subsystem failures



This change provides provision to capture fatal errors
reported by FW and enables WD interrupt from A5. In such cases
FW will be downloaded again before next USECASE starts,
even if power collpase is enabled.

Change-Id: I04aef9a55a7e1312344bdec5221e1c318cf1ef82
Signed-off-by: default avatarAlok Pandey <akumarpa@codeaurora.org>
Signed-off-by: default avatarKarthik Anantha Ram <kartanan@codeaurora.org>
parent 7c121a05
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -35,6 +35,7 @@ struct hfi_mem {
 * @cmd_q: command queue hfi memory for host to firmware communication
 * @msg_q: message queue hfi memory for firmware to host communication
 * @dbg_q: debug queue hfi memory for firmware debug information
 * @sfr_buf: buffer for subsystem failure reason[SFR]
 * @sec_heap: secondary heap hfi memory for firmware
 * @qdss: qdss mapped memory for fw
 * @icp_base: icp base address
@@ -44,6 +45,7 @@ struct hfi_mem_info {
	struct hfi_mem cmd_q;
	struct hfi_mem msg_q;
	struct hfi_mem dbg_q;
	struct hfi_mem sfr_buf;
	struct hfi_mem sec_heap;
	struct hfi_mem shmem;
	struct hfi_mem qdss;
+17 −1
Original line number Diff line number Diff line
@@ -43,6 +43,7 @@
#define HFI_REG_UNCACHED_HEAP_SIZE              0x60
#define HFI_REG_QDSS_IOVA                       0x6C
#define HFI_REG_QDSS_IOVA_SIZE                  0x70
#define HFI_REG_SFR_PTR                         0x68
/* end of ICP CSR registers */

/* flags for ICP CSR registers */
@@ -72,6 +73,7 @@
#define ICP_CMD_Q_SIZE_IN_BYTES                 4096
#define ICP_MSG_Q_SIZE_IN_BYTES                 4096
#define ICP_DBG_Q_SIZE_IN_BYTES                 102400
#define ICP_MSG_SFR_SIZE_IN_BYTES               4096

#define ICP_SHARED_MEM_IN_BYTES                 (1024 * 1024)
#define ICP_UNCACHED_HEAP_SIZE_IN_BYTES         (2 * 1024 * 1024)
@@ -128,10 +130,14 @@ enum reg_settings {
/**
 * @INTR_DISABLE: Disable interrupt
 * @INTR_ENABLE: Enable interrupt
 * @INTR_ENABLE_WD0: Enable WD0
 * @INTR_ENABLE_WD1: Enable WD1
 */
enum intr_status {
	INTR_DISABLE,
	INTR_ENABLE
	INTR_ENABLE,
	INTR_ENABLE_WD0,
	INTR_ENABLE_WD1 = 0x4
};

/**
@@ -285,6 +291,16 @@ struct hfi_q_hdr {
	uint32_t dummy14[15];
};

/**
 * struct sfr_buf
 * @size: Number of characters
 * @msg : Subsystem failure reason
 */
struct sfr_buf {
	uint32_t size;
	char msg[ICP_MSG_SFR_SIZE_IN_BYTES];
};

/**
 * struct hfi_q_tbl
 * @q_tbl_hdr: Queue table header
+12 −3
Original line number Diff line number Diff line
@@ -600,7 +600,7 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem,
		return -EINVAL;
	}

	cam_io_w_mb((uint32_t)INTR_ENABLE,
	cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0),
		icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);

	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
@@ -610,6 +610,8 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem,
	CAM_DBG(CAM_HFI, "wfi status = %x", (int)data);

	cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
	cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova,
		icp_base + HFI_REG_SFR_PTR);
	cam_io_w_mb((uint32_t)hfi_mem->shmem.iova,
		icp_base + HFI_REG_SHARED_MEM_PTR);
	cam_io_w_mb((uint32_t)hfi_mem->shmem.len,
@@ -635,6 +637,7 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
	struct hfi_q_hdr *cmd_q_hdr, *msg_q_hdr, *dbg_q_hdr;
	uint32_t hw_version, soc_version, fw_version, status = 0;
	uint32_t retry_cnt = 0;
	struct sfr_buf *sfr_buffer;

	mutex_lock(&hfi_cmd_q_mutex);
	mutex_lock(&hfi_msg_q_mutex);
@@ -716,6 +719,9 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
	dbg_q_hdr->qhdr_read_idx = RESET;
	dbg_q_hdr->qhdr_write_idx = RESET;

	sfr_buffer = (struct sfr_buf *)hfi_mem->sfr_buf.kva;
	sfr_buffer->size = ICP_MSG_SFR_SIZE_IN_BYTES;

	switch (event_driven_mode) {
	case INTR_MODE:
		cmd_q_hdr->qhdr_type = Q_CMD;
@@ -788,7 +794,10 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
		break;
	}

	cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
	cam_io_w_mb((uint32_t)hfi_mem->qtbl.iova,
		icp_base + HFI_REG_QTBL_PTR);
	cam_io_w_mb((uint32_t)hfi_mem->sfr_buf.iova,
		icp_base + HFI_REG_SFR_PTR);
	cam_io_w_mb((uint32_t)hfi_mem->shmem.iova,
		icp_base + HFI_REG_SHARED_MEM_PTR);
	cam_io_w_mb((uint32_t)hfi_mem->shmem.len,
@@ -845,7 +854,7 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
	g_hfi->hfi_state = HFI_READY;
	g_hfi->cmd_q_state = true;
	g_hfi->msg_q_state = true;
	cam_io_w_mb((uint32_t)INTR_ENABLE,
	cam_io_w_mb((uint32_t)(INTR_ENABLE|INTR_ENABLE_WD0),
		icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);

	mutex_unlock(&hfi_cmd_q_mutex);
+2 −2
Original line number Diff line number Diff line
@@ -25,8 +25,8 @@
#define A5_CSR_BASE             2

#define A5_HOST_INT             0x1
#define A5_WDT_0                0x10
#define A5_WDT_1                0x100
#define A5_WDT_0                0x2
#define A5_WDT_1                0x4

#define ELF_GUARD_PAGE          (2 * 1024 * 1024)

+80 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#include <linux/firmware.h>
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/iopoll.h>
#include "cam_io_util.h"
#include "cam_hw.h"
#include "cam_hw_intf.h"
@@ -30,6 +31,9 @@
#include "cam_icp_hw_mgr_intf.h"
#include "cam_cpas_api.h"
#include "cam_debug_util.h"
#include "hfi_reg.h"

#define HFI_MAX_POLL_TRY 5

static int cam_bps_cpas_vote(struct cam_bps_device_core_info *core_info,
			struct cam_icp_cpas_vote *cpas_vote)
@@ -210,6 +214,77 @@ static int cam_bps_handle_resume(struct cam_hw_info *bps_dev)
	return rc;
}

static int cam_bps_cmd_reset(struct cam_hw_soc_info *soc_info,
	struct cam_bps_device_core_info *core_info)
{
	uint32_t retry_cnt = 0;
	uint32_t status = 0;
	int pwr_ctrl, pwr_status, rc = 0;
	bool reset_bps_cdm_fail = false;
	bool reset_bps_top_fail = false;

	CAM_DBG(CAM_ICP, "CAM_ICP_BPS_CMD_RESET");
	/* Reset BPS CDM core*/
	cam_io_w_mb((uint32_t)0xF,
		soc_info->reg_map[0].mem_base + BPS_CDM_RST_CMD);
	while (retry_cnt < HFI_MAX_POLL_TRY) {
		readw_poll_timeout((soc_info->reg_map[0].mem_base +
			BPS_CDM_IRQ_STATUS),
			status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1),
			100, 10000);

		CAM_DBG(CAM_ICP, "bps_cdm_irq_status = %u", status);

		if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1)
			break;
		retry_cnt++;
	}
	status = cam_io_r_mb(soc_info->reg_map[0].mem_base +
		BPS_CDM_IRQ_STATUS);
	if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) {
		CAM_ERR(CAM_ICP, "BPS CDM rst failed status 0x%x", status);
		reset_bps_cdm_fail = true;
	}

	/* Reset BPS core*/
	status = 0;
	cam_io_w_mb((uint32_t)0x3,
		soc_info->reg_map[0].mem_base + BPS_TOP_RST_CMD);
	while (retry_cnt < HFI_MAX_POLL_TRY) {
		readw_poll_timeout((soc_info->reg_map[0].mem_base +
			BPS_TOP_IRQ_STATUS),
			status, ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1),
			100, 10000);

		CAM_DBG(CAM_ICP, "bps_top_irq_status = %u", status);

		if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) == 0x1)
			break;
		retry_cnt++;
	}
	status = cam_io_r_mb(soc_info->reg_map[0].mem_base +
		BPS_TOP_IRQ_STATUS);
	if ((status & BPS_RST_DONE_IRQ_STATUS_BIT) != 0x1) {
		CAM_ERR(CAM_ICP, "BPS top rst failed status 0x%x", status);
		reset_bps_top_fail = true;
	}

	cam_bps_get_gdsc_control(soc_info);
	cam_cpas_reg_read(core_info->cpas_handle,
		CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_ctrl,
		true, &pwr_ctrl);
	cam_cpas_reg_read(core_info->cpas_handle,
		CAM_CPAS_REG_CPASTOP, core_info->bps_hw_info->pwr_status,
		true, &pwr_status);
	CAM_DBG(CAM_ICP, "(After) pwr_ctrl = %x pwr_status = %x",
		pwr_ctrl, pwr_status);

	if (reset_bps_cdm_fail || reset_bps_top_fail)
		rc = -EAGAIN;

	return rc;
}

int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type,
	void *cmd_args, uint32_t arg_size)
{
@@ -311,7 +386,12 @@ int cam_bps_process_cmd(void *device_priv, uint32_t cmd_type,
			cam_bps_toggle_clk(soc_info, false);
		core_info->clk_enable = false;
		break;
	case CAM_ICP_BPS_CMD_RESET:
		rc = cam_bps_cmd_reset(soc_info, core_info);
		break;
	default:
		CAM_ERR(CAM_ICP, "Invalid Cmd Type:%u", cmd_type);
		rc = -EINVAL;
		break;
	}
	return rc;
Loading