Forráskód Böngészése

msm: camera: icp: Add mechanism to verify IRQ lines

IRQ line verification can now be triggerred from ICP HW manager by
writing to a debugfs file as follows:
    echo 1 > /d/camera/icp/test_irq_line

IRQ line verification can also be done at probe if
CONFIG_CAM_TEST_IRQ_LINE_AT_PROBE is set to true during compilation.
Both debugfs and probe-time verifications are only active if
CONFIG_CAM_TEST_IRQ_LINE is set to true during compilation.

CRs-Fixed: 3071027
Change-Id: I386548d1ed817674be8322c8be792e2c57f9d166
Signed-off-by: Anand Ravi <[email protected]>
Anand Ravi 3 éve
szülő
commit
af9072bcc6

+ 62 - 0
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c

@@ -1,6 +1,7 @@
 // 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/uaccess.h>
@@ -1956,6 +1957,62 @@ static const struct file_operations cam_icp_hw_mgr_fw_load_options = {
 };
 #endif
 
+#ifdef CONFIG_CAM_TEST_IRQ_LINE
+
+static int cam_icp_test_irq_line(void)
+{
+	int rc = -EINVAL;
+
+	if (icp_hw_mgr.icp_dev_intf->hw_ops.test_irq_line)
+		rc = icp_hw_mgr.icp_dev_intf->hw_ops.test_irq_line(
+			icp_hw_mgr.icp_dev_intf->hw_priv);
+
+	if (rc)
+		CAM_ERR(CAM_ICP, "failed to verify IRQ line for ICP");
+
+	return 0;
+}
+
+#else
+
+static int cam_icp_test_irq_line(void)
+{
+	CAM_ERR(CAM_ICP, "IRQ line verification disabled!");
+	return -EPERM;
+}
+
+#endif
+
+#if (defined(CONFIG_CAM_TEST_IRQ_LINE) && defined(CONFIG_CAM_TEST_IRQ_LINE_AT_PROBE))
+
+static int cam_icp_test_irq_line_at_probe(void)
+{
+	return cam_icp_test_irq_line();
+}
+
+#else
+
+static int cam_icp_test_irq_line_at_probe(void)
+{
+	return 0;
+}
+
+#endif
+
+static int cam_icp_set_irq_line_test(void *data, u64 val)
+{
+	cam_icp_test_irq_line();
+	return 0;
+}
+
+static int cam_icp_get_irq_line_test(void *data, u64 *val)
+{
+	return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(cam_icp_irq_line_test, cam_icp_get_irq_line_test,
+	cam_icp_set_irq_line_test, "%08llu");
+
 static int cam_icp_hw_mgr_create_debugfs_entry(void)
 {
 	int rc = 0;
@@ -2001,6 +2058,8 @@ static int cam_icp_hw_mgr_create_debugfs_entry(void)
 		debugfs_create_file("icp_fw_load_unload", 0644,
 			icp_hw_mgr.dentry, NULL, &cam_icp_hw_mgr_fw_load_options);
 	#endif
+	debugfs_create_file("test_irq_line", 0644,
+		icp_hw_mgr.dentry, NULL, &cam_icp_irq_line_test);
 
 end:
 	/* Set default hang dump lvl */
@@ -6785,6 +6844,9 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 	init_completion(&icp_hw_mgr.icp_complete);
 	cam_common_register_mini_dump_cb(
 		cam_icp_hw_mgr_mini_dump_cb, "cam_icp");
+
+	cam_icp_test_irq_line_at_probe();
+
 	return rc;
 
 icp_wq_create_failed:

+ 48 - 2
drivers/cam_icp/icp_hw/lx7_hw/lx7_core.c

@@ -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.
  */
 
 #include <linux/of_address.h>
@@ -33,6 +34,8 @@
 #define PC_POLL_DELAY_US 100
 #define PC_POLL_TIMEOUT_US 10000
 
+#define LX7_IRQ_TEST_TIMEOUT 1000
+
 static int cam_lx7_ubwc_configure(struct cam_hw_soc_info *soc_info)
 {
 	int i = 0, rc, ddr_type;
@@ -904,6 +907,7 @@ irqreturn_t cam_lx7_handle_irq(int irq_num, void *data)
 		return IRQ_NONE;
 	}
 
+	core_info = lx7_info->core_info;
 	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);
@@ -911,6 +915,13 @@ irqreturn_t cam_lx7_handle_irq(int irq_num, void *data)
 	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 (core_info->is_irq_test) {
+		CAM_INFO(CAM_ICP, "LX7 IRQ verified (status=0x%x)", status);
+		core_info->is_irq_test = false;
+		complete(&lx7_info->hw_complete);
+		return IRQ_HANDLED;
+	}
+
 	if (status & LX7_WDT_BITE_WS0) {
 		/* WD clear sequence - SW listens only to WD0 */
 		cam_io_w_mb(0x0,
@@ -923,8 +934,6 @@ irqreturn_t cam_lx7_handle_irq(int irq_num, void *data)
 		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,
@@ -962,6 +971,43 @@ void cam_lx7_irq_enable(void *priv)
 		ICP_LX7_CIRQ_OB_MASK);
 }
 
+int cam_lx7_test_irq_line(void *priv)
+{
+	struct cam_hw_info *lx7_info = priv;
+	struct cam_lx7_core_info *core_info = NULL;
+	void __iomem *cirq_membase;
+	unsigned long rem_jiffies;
+
+	if (!lx7_info) {
+		CAM_ERR(CAM_ICP, "invalid LX7 device info");
+		return -EINVAL;
+	}
+
+	core_info = lx7_info->core_info;
+	cirq_membase = lx7_info->soc_info.reg_map[LX7_CIRQ_BASE].mem_base;
+
+	reinit_completion(&lx7_info->hw_complete);
+	core_info->is_irq_test = true;
+
+	cam_lx7_hw_init(priv, NULL, 0);
+
+	cam_io_w_mb(LX7_WDT_BARK_WS0, cirq_membase + ICP_LX7_CIRQ_OB_MASK);
+	cam_io_w_mb(LX7_WDT_BARK_WS0, cirq_membase + ICP_LX7_CIRQ_OB_SET);
+	cam_io_w_mb(LX7_IRQ_SET_CMD, cirq_membase + ICP_LX7_CIRQ_OB_IRQ_CMD);
+
+	rem_jiffies = cam_common_wait_for_completion_timeout(&lx7_info->hw_complete,
+		msecs_to_jiffies(LX7_IRQ_TEST_TIMEOUT));
+	if (!rem_jiffies)
+		CAM_ERR(CAM_ICP, "LX7 IRQ verification timed out");
+
+	cam_io_w_mb(0, cirq_membase + ICP_LX7_CIRQ_OB_MASK);
+	cam_lx7_hw_deinit(priv, NULL, 0);
+
+	core_info->is_irq_test = false;
+
+	return 0;
+}
+
 void __iomem *cam_lx7_iface_addr(void *priv)
 {
 	struct cam_hw_info *lx7_info = priv;

+ 3 - 0
drivers/cam_icp/icp_hw/lx7_hw/lx7_core.h

@@ -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_LX7_CORE_H_
@@ -25,6 +26,7 @@ struct cam_lx7_core_info {
 	uint32_t cpas_handle;
 	bool cpas_start;
 	bool use_sec_pil;
+	bool is_irq_test;
 	struct {
 		const struct firmware *fw_elf;
 		void *fw;
@@ -38,6 +40,7 @@ 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);

+ 2 - 0
drivers/cam_icp/icp_hw/lx7_hw/lx7_dev.c

@@ -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.
  */
 
 #include <linux/module.h>
@@ -70,6 +71,7 @@ static int cam_lx7_component_bind(struct device *dev,
 	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) {

+ 3 - 0
drivers/cam_icp/icp_hw/lx7_hw/lx7_reg.h

@@ -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_LX7_REG_H_
@@ -18,6 +19,7 @@
 
 #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 */
@@ -33,6 +35,7 @@
 
 #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