فهرست منبع

msm: camera: isp: Skip writes to clean IRQ clear registers

If an IRQ status register has not caused the interrupt to be triggered,
we can skip writing to the corresponding clear register as long as no
previous writes have been made to it that will cause bits of interest to
be cleared (i.e. clear register is dirty). For this, we maintain a dirty
flag for each clear register.

The dirty flag will never cause false negatives (i.e. valid writes to be
missed) since hardware cannot set any bits in the clear register to 1
and will only clear the entire register upon resetting the hardware.

CRs-Fixed: 3152588
Change-Id: I4f97bae0e3cd983ca66d5b89ffb2c16da7c25200
Signed-off-by: Anand Ravi <[email protected]>
Anand Ravi 3 سال پیش
والد
کامیت
340e043307
1فایلهای تغییر یافته به همراه30 افزوده شده و 0 حذف شده
  1. 30 0
      drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c

+ 30 - 0
drivers/cam_isp/isp_hw_mgr/hw_utils/irq_controller/cam_irq_controller.c

@@ -69,6 +69,7 @@ struct cam_irq_evt_handler {
  *                          after subscribe/unsubscribe calls
  * @dependent_read_mask:    Mask to check if any dependent controllers' read needs to triggered
  *                          from independent controller
+ * @dirty_clear:            Flag to identify if clear register contains non-zero value
  */
 struct cam_irq_register_obj {
 	uint32_t                     index;
@@ -81,6 +82,7 @@ struct cam_irq_register_obj {
 	uint32_t                     top_half_enable_mask[CAM_IRQ_PRIORITY_MAX];
 	uint32_t                     aggr_mask;
 	uint32_t                     dependent_read_mask[CAM_IRQ_MAX_DEPENDENTS];
+	bool                         dirty_clear;
 };
 
 /**
@@ -407,6 +409,7 @@ int cam_irq_controller_init(const char       *name,
 			register_info->irq_reg_set[i].test_set_val;
 		controller->irq_register_arr[i].test_sub_val =
 			register_info->irq_reg_set[i].test_sub_val;
+		controller->irq_register_arr[i].dirty_clear = true;
 		CAM_DBG(CAM_IRQ_CTRL, "i %d mask_reg_offset: 0x%x", i,
 			controller->irq_register_arr[i].mask_reg_offset);
 		CAM_DBG(CAM_IRQ_CTRL, "i %d clear_reg_offset: 0x%x", i,
@@ -487,6 +490,7 @@ static inline void __cam_irq_controller_enable_irq(
 		irq_register = &controller->irq_register_arr[i];
 		irq_register->top_half_enable_mask[priority] |= update_mask[i];
 		irq_register->aggr_mask |= update_mask[i];
+		irq_register->dirty_clear = true;
 		cam_io_w_mb(irq_register->aggr_mask, controller->mem_base +
 			irq_register->mask_reg_offset);
 	}
@@ -865,6 +869,32 @@ static void __cam_irq_controller_read_registers(struct cam_irq_controller *contr
 			controller->irq_register_arr[i].status_reg_offset,
 			controller->irq_status_arr[i]);
 
+		/**
+		 * If this status register has not caused the interrupt to be
+		 * triggered, we can skip writing to the clear register as long
+		 * as no previous writes have been made to it that will cause
+		 * bits of interest to be cleared (i.e. clear register is
+		 * dirty).
+		 *
+		 * The dirty clear flag will never cause false negatives (i.e.
+		 * valid writes to be missed) since hardware cannot set any bits
+		 * in the clear register to 1 and will only clear the entire
+		 * register upon resetting the hardware.
+		 */
+		if (!(controller->irq_status_arr[i] & irq_register->aggr_mask)) {
+			if (!irq_register->dirty_clear)
+				continue;
+			else
+				irq_register->dirty_clear = false;
+		} else {
+			irq_register->dirty_clear = true;
+		}
+
+		CAM_DBG(CAM_IRQ_CTRL, "(%s) Write irq clear%d (0x%x) = 0x%x (dirty=%s)",
+			controller->name, i, controller->irq_register_arr[i].clear_reg_offset,
+			controller->irq_status_arr[i],
+			CAM_BOOL_TO_YESNO(irq_register->dirty_clear));
+
 		cam_io_w(controller->irq_status_arr[i],
 			controller->mem_base + irq_register->clear_reg_offset);
 	}