fix(gic600): implement workaround to forward highest priority interrupt

If the interrupt being targeted is released from the CPU before the
CLEAR command is sent to the CPU then a subsequent SET command may not
be delivered in a finite time. To workaround this, issue an unblocking
event by toggling GICR_CTLR.DPG* bits after clearing the cpu group
enable (EnableGrp* bits of GIC CPU interface register)
This fix is implemented as per the errata 2384374-part 2 workaround
mentioned here:
https://developer.arm.com/documentation/sden892601/latest/

Change-Id: I13926ceeb7740fa4c05cc5b43170e7ce49598f70
Signed-off-by: Manish V Badarkhe <Manish.Badarkhe@arm.com>
diff --git a/drivers/arm/gic/v3/gic-x00.c b/drivers/arm/gic/v3/gic-x00.c
index aaef485..75eb69a 100644
--- a/drivers/arm/gic/v3/gic-x00.c
+++ b/drivers/arm/gic/v3/gic-x00.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2020, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2022, Arm Limited and Contributors. All rights reserved.
  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -42,6 +42,8 @@
 #define PWRR_ON				(0U << PWRR_RDPD_SHIFT)
 #define PWRR_OFF			(1U << PWRR_RDPD_SHIFT)
 
+static bool gic600_errata_wa_2384374 __unused;
+
 #if GICV3_SUPPORT_GIC600
 
 /* GIC-600/700 specific accessor functions */
@@ -170,3 +172,60 @@
 	}
 #endif
 }
+
+#if GIC600_ERRATA_WA_2384374
+/*******************************************************************************
+ * Apply part 2 of workaround for errata-2384374 as per SDEN:
+ * https://developer.arm.com/documentation/sden892601/latest/
+ ******************************************************************************/
+void gicv3_apply_errata_wa_2384374(uintptr_t gicr_base)
+{
+	if (gic600_errata_wa_2384374) {
+		uint32_t gicr_ctlr_val = gicr_read_ctlr(gicr_base);
+
+		gicr_write_ctlr(gicr_base, gicr_ctlr_val |
+				(GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT |
+				GICR_CTLR_DPG1S_BIT));
+		gicr_write_ctlr(gicr_base, gicr_ctlr_val &
+				~(GICR_CTLR_DPG0_BIT | GICR_CTLR_DPG1NS_BIT |
+				  GICR_CTLR_DPG1S_BIT));
+	}
+}
+#endif /* GIC600_ERRATA_WA_2384374 */
+
+void gicv3_check_erratas_applies(uintptr_t gicd_base)
+{
+	unsigned int gic_prod_id;
+	uint8_t gic_rev;
+
+	assert(gicd_base != 0UL);
+
+	gicv3_get_component_prodid_rev(gicd_base, &gic_prod_id, &gic_rev);
+
+	/*
+	 * This workaround applicable only to GIC600 and GIC600AE products with
+	 * revision less than r1p6 and r0p2 respectively.
+	 * As per GIC600/GIC600AE specification -
+	 * r1p6 = 0x17 => GICD_IIDR[19:12]
+	 * r0p2 = 0x04 => GICD_IIDR[19:12]
+	 */
+	if ((gic_prod_id == GIC_PRODUCT_ID_GIC600) ||
+		    (gic_prod_id == GIC_PRODUCT_ID_GIC600AE)) {
+		if (((gic_prod_id == GIC_PRODUCT_ID_GIC600) &&
+		     (gic_rev <= GIC_REV(GIC_VARIANT_R1, GIC_REV_P6))) ||
+		     ((gic_prod_id == GIC_PRODUCT_ID_GIC600AE) &&
+		     (gic_rev <= GIC_REV(GIC_VARIANT_R0, GIC_REV_P2)))) {
+#if GIC600_ERRATA_WA_2384374
+			gic600_errata_wa_2384374 = true;
+			VERBOSE("%s applies\n",
+				"GIC600/GIC600AE errata workaround 2384374");
+#else
+			WARN("%s missing\n",
+			     "GIC600/GIC600AE errata workaround 2384374");
+#endif /* GIC600_ERRATA_WA_2384374 */
+		} else {
+			VERBOSE("%s not applies\n",
+				"GIC600/GIC600AE errata workaround 2384374");
+		}
+	}
+}