Prepare platforms to use refactored ARM GIC drivers
authorSoby Mathew <soby.mathew@arm.com>
Mon, 26 Oct 2015 14:01:53 +0000 (14:01 +0000)
committerSoby Mathew <soby.mathew@arm.com>
Wed, 9 Dec 2015 09:56:53 +0000 (09:56 +0000)
This patch adds platform helpers for the new GICv2 and GICv3 drivers in
plat_gicv2.c and plat_gicv3.c. The platforms can include the appropriate
file in their build according to the GIC driver to be used. The existing
plat_gic.c is only meant for the legacy GIC driver.

In the case of ARM platforms, the major changes are as follows:

1. The crash reporting helper macro `arm_print_gic_regs` that prints the GIC CPU
   interface register values has been modified to detect the type of CPU
   interface being used (System register or memory mappped interface) before
   using the right interface to print the registers.

2. The power management helper function that is called after a core is powered
   up has been further refactored. This is to highlight that the per-cpu
   distributor interface should be initialised only when the core was originally
   powered down using the CPU_OFF PSCI API and not when the CPU_SUSPEND PSCI API
   was used.

3. In the case of CSS platforms, the system power domain restore helper
   `arm_system_pwr_domain_resume()` is now only invoked in the `suspend_finish`
   handler as the system power domain is always expected to be initialized when
   the `on_finish` handler is invoked.

Change-Id: I7fc27d61fc6c2a60cea2436b676c5737d0257df6

include/plat/arm/common/aarch64/arm_macros.S
plat/arm/board/fvp/aarch64/fvp_helpers.S
plat/arm/board/fvp/fvp_pm.c
plat/arm/board/fvp/include/plat_macros.S
plat/arm/css/common/css_pm.c
plat/common/plat_gicv2.c [new file with mode: 0644]
plat/common/plat_gicv3.c [new file with mode: 0644]

index 594b0965928ea2704341718824ed6fc0a55a6b14..eaaa62fe1ca9e467e31e5affeb3d475b5b6b6ac6 100644 (file)
 #define __ARM_MACROS_S__
 
 #include <cci.h>
-#include <gic_v2.h>
+#include <gic_common.h>
+#include <gicv2.h>
+#include <gicv3.h>
 #include <platform_def.h>
 
 .section .rodata.gic_reg_name, "aS"
+/* Applicable only to GICv2 and GICv3 with SRE disabled (legacy mode) */
 gicc_regs:
        .asciz "gicc_hppir", "gicc_ahppir", "gicc_ctlr", ""
+
+/* Applicable only to GICv3 with SRE enabled */
+icc_regs:
+       .asciz "icc_hppir0_el1", "icc_hppir1_el1", "icc_ctlr_el3", ""
+
+/* Registers common to both GICv2 and GICv3 */
 gicd_pend_reg:
        .asciz "gicd_ispendr regs (Offsets 0x200 - 0x278)\n"    \
                " Offset:\t\t\tvalue\n"
@@ -54,6 +63,28 @@ spacer:
         * ---------------------------------------------
         */
        .macro arm_print_gic_regs
+       /* Check for GICv3 system register access */
+       mrs     x7, id_aa64pfr0_el1
+       ubfx    x7, x7, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+       cmp     x7, #1
+       b.ne    print_gicv2
+
+       /* Check for SRE enable */
+       mrs     x8, ICC_SRE_EL3
+       tst     x8, #ICC_SRE_SRE_BIT
+       b.eq    print_gicv2
+
+       /* Load the icc reg list to x6 */
+       adr     x6, icc_regs
+       /* Load the icc regs to gp regs used by str_in_crash_buf_print */
+       mrs     x8, ICC_HPPIR0_EL1
+       mrs     x9, ICC_HPPIR1_EL1
+       mrs     x10, ICC_CTLR_EL3
+       /* Store to the crash buf and print to console */
+       bl      str_in_crash_buf_print
+       b       print_gic_common
+
+print_gicv2:
        /* Load the gicc reg list to x6 */
        adr     x6, gicc_regs
        /* Load the gicc regs to gp regs used by str_in_crash_buf_print */
@@ -63,6 +94,7 @@ spacer:
        /* Store to the crash buf and print to console */
        bl      str_in_crash_buf_print
 
+print_gic_common:
        /* Print the GICD_ISPENDR regs */
        add     x7, x16, #GICD_ISPENDR
        adr     x4, gicd_pend_reg
index 2c24e61f95c09874db837a3ef21c9e34465b94ad..338d15813cace5e745b5c9bfc857aee3bb9632c2 100644 (file)
@@ -30,7 +30,8 @@
 
 #include <arch.h>
 #include <asm_macros.S>
-#include <gic_v2.h>
+#include <gicv2.h>
+#include <gicv3.h>
 #include <platform_def.h>
 #include <v2m_def.h>
 #include "../drivers/pwrc/fvp_pwrc.h"
@@ -74,9 +75,26 @@ func plat_secondary_cold_boot_setup
        str     w0, [x1, #PPOFFR_OFF]
 
        /* ---------------------------------------------
-        * Deactivate the gic cpu interface as well
+        * Disable GIC bypass as well
         * ---------------------------------------------
         */
+       /* Check for GICv3 system register access */
+       mrs     x0, id_aa64pfr0_el1
+       ubfx    x0, x0, #ID_AA64PFR0_GIC_SHIFT, #ID_AA64PFR0_GIC_WIDTH
+       cmp     x0, #1
+       b.ne    gicv2_bypass_disable
+
+       /* Check for SRE enable */
+       mrs     x1, ICC_SRE_EL3
+       tst     x1, #ICC_SRE_SRE_BIT
+       b.eq    gicv2_bypass_disable
+
+       mrs     x2, ICC_SRE_EL3
+       orr     x2, x2, #(ICC_SRE_DIB_BIT | ICC_SRE_DFB_BIT)
+       msr     ICC_SRE_EL3, x2
+       b       secondary_cold_boot_wait
+
+gicv2_bypass_disable:
        ldr     x0, =VE_GICC_BASE
        ldr     x1, =BASE_GICC_BASE
        fvp_choose_gicmmap      x0, x1, x2, w2, x1
@@ -84,6 +102,7 @@ func plat_secondary_cold_boot_setup
        orr     w0, w0, #(IRQ_BYP_DIS_GRP0 | FIQ_BYP_DIS_GRP0)
        str     w0, [x1, #GICC_CTLR]
 
+secondary_cold_boot_wait:
        /* ---------------------------------------------
         * There is no sane reason to come out of this
         * wfi so panic if we do. This cpu will be pow-
index 21ad14fa5e8c52d846dc973825ca66a00d6fdace..d7b459d78fbc53ce10f3eb258222672d6581957a 100644 (file)
@@ -93,6 +93,42 @@ static void fvp_cluster_pwrdwn_common(void)
        fvp_pwrc_write_pcoffr(mpidr);
 }
 
+static void fvp_power_domain_on_finish_common(const psci_power_state_t *target_state)
+{
+       unsigned long mpidr;
+
+       assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
+                                       ARM_LOCAL_STATE_OFF);
+
+       /* Get the mpidr for this cpu */
+       mpidr = read_mpidr_el1();
+
+       /* Perform the common cluster specific operations */
+       if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
+                                       ARM_LOCAL_STATE_OFF) {
+               /*
+                * This CPU might have woken up whilst the cluster was
+                * attempting to power down. In this case the FVP power
+                * controller will have a pending cluster power off request
+                * which needs to be cleared by writing to the PPONR register.
+                * This prevents the power controller from interpreting a
+                * subsequent entry of this cpu into a simple wfi as a power
+                * down request.
+                */
+               fvp_pwrc_write_pponr(mpidr);
+
+               /* Enable coherency if this cluster was off */
+               fvp_cci_enable();
+       }
+
+       /*
+        * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
+        * with a cpu power down unless the bit is set again
+        */
+       fvp_pwrc_clr_wen(mpidr);
+}
+
+
 /*******************************************************************************
  * FVP handler called when a CPU is about to enter standby.
  ******************************************************************************/
@@ -196,42 +232,11 @@ void fvp_pwr_domain_suspend(const psci_power_state_t *target_state)
  ******************************************************************************/
 void fvp_pwr_domain_on_finish(const psci_power_state_t *target_state)
 {
-       unsigned long mpidr;
-
-       assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-                                       ARM_LOCAL_STATE_OFF);
-
-       /* Get the mpidr for this cpu */
-       mpidr = read_mpidr_el1();
-
-       /* Perform the common cluster specific operations */
-       if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
-                                       ARM_LOCAL_STATE_OFF) {
-               /*
-                * This CPU might have woken up whilst the cluster was
-                * attempting to power down. In this case the FVP power
-                * controller will have a pending cluster power off request
-                * which needs to be cleared by writing to the PPONR register.
-                * This prevents the power controller from interpreting a
-                * subsequent entry of this cpu into a simple wfi as a power
-                * down request.
-                */
-               fvp_pwrc_write_pponr(mpidr);
-
-               /* Enable coherency if this cluster was off */
-               fvp_cci_enable();
-       }
-
-       /*
-        * Clear PWKUPR.WEN bit to ensure interrupts do not interfere
-        * with a cpu power down unless the bit is set again
-        */
-       fvp_pwrc_clr_wen(mpidr);
+       fvp_power_domain_on_finish_common(target_state);
 
        /* Enable the gic cpu interface */
        arm_gic_cpuif_setup();
-
-       /* TODO: This setup is needed only after a cold boot */
+       /* Program the gic per-cpu distributor interface */
        arm_gic_pcpu_distif_setup();
 }
 
@@ -251,7 +256,10 @@ void fvp_pwr_domain_suspend_finish(const psci_power_state_t *target_state)
                                        ARM_LOCAL_STATE_RET)
                return;
 
-       fvp_pwr_domain_on_finish(target_state);
+       fvp_power_domain_on_finish_common(target_state);
+
+       /* Enable the gic cpu interface */
+       arm_gic_cpuif_setup();
 }
 
 /*******************************************************************************
index 2feffbe521c47b94297b1a1339ac0e8eb43f4186..2ed0d85e9f1887c14fdb6788067bc0a2bfd8e95f 100644 (file)
        /* Check if VE mmap */
        cmp     w16, #BLD_GIC_VE_MMAP
        b.eq    use_ve_mmap
-       /* Check if Cortex-A53/A57 mmap */
-       cmp     w16, #BLD_GIC_A53A57_MMAP
-       b.ne    exit_print_gic_regs
+       /* Assume Base Cortex mmap */
        mov_imm x17, BASE_GICC_BASE
        mov_imm x16, BASE_GICD_BASE
-       b       print_gicc_regs
+       b       print_gic_regs
 use_ve_mmap:
        mov_imm x17, VE_GICC_BASE
        mov_imm x16, VE_GICD_BASE
-print_gicc_regs:
+print_gic_regs:
        arm_print_gic_regs
        .endm
 
index 3f468570e164d4fa849026bc6cbeb1f5966ef6dd..1d9bd59479d86efa84e1f954f7f49f81eb74bcd6 100644 (file)
 #include <platform_def.h>
 #include "css_scpi.h"
 
+/* Macros to read the CSS power domain state */
+#define CSS_CORE_PWR_STATE(state)      (state)->pwr_domain_state[ARM_PWR_LVL0]
+#define CSS_CLUSTER_PWR_STATE(state)   (state)->pwr_domain_state[ARM_PWR_LVL1]
+#define CSS_SYSTEM_PWR_STATE(state)    ((PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) ?\
+                               (state)->pwr_domain_state[ARM_PWR_LVL2] : 0)
+
 /* Allow CSS platforms to override `plat_arm_psci_pm_ops` */
 #pragma weak plat_arm_psci_pm_ops
 
@@ -93,50 +99,37 @@ int css_pwr_domain_on(u_register_t mpidr)
        return PSCI_E_SUCCESS;
 }
 
-/*******************************************************************************
- * Handler called when a power level has just been powered on after
- * being turned off earlier. The target_state encodes the low power state that
- * each level has woken up from.
- ******************************************************************************/
-void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
+static void css_pwr_domain_on_finisher_common(
+               const psci_power_state_t *target_state)
 {
-       assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-                                               ARM_LOCAL_STATE_OFF);
-
-       if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
-               /*
-                * Perform system initialization if woken up from system
-                * suspend.
-                */
-               if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
-                                                       ARM_LOCAL_STATE_OFF)
-                       arm_system_pwr_domain_resume();
-       }
+       assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
 
        /*
         * Perform the common cluster specific operations i.e enable coherency
         * if this cluster was off.
         */
-       if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
-                                               ARM_LOCAL_STATE_OFF)
+       if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
                cci_enable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr_el1()));
+}
 
+/*******************************************************************************
+ * Handler called when a power level has just been powered on after
+ * being turned off earlier. The target_state encodes the low power state that
+ * each level has woken up from. This handler would never be invoked with
+ * the system power domain uninitialized as either the primary would have taken
+ * care of it as part of cold boot or the first core awakened from system
+ * suspend would have already initialized it.
+ ******************************************************************************/
+void css_pwr_domain_on_finish(const psci_power_state_t *target_state)
+{
+       /* Assert that the system power domain need not be initialized */
+       assert(CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_RUN);
 
-       if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
-               /*
-                * Skip GIC CPU interface and per-CPU Distributor interface
-                * setups if woken up from system suspend as it is done as
-                * part of css_system_pwr_domain_resume().
-                */
-               if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
-                                                       ARM_LOCAL_STATE_OFF)
-                       return;
-       }
+       css_pwr_domain_on_finisher_common(target_state);
 
        /* Enable the gic cpu interface */
        arm_gic_cpuif_setup();
-
-       /* todo: Is this setup only needed after a cold boot? */
+       /* Program the gic per-cpu distributor interface */
        arm_gic_pcpu_distif_setup();
 }
 
@@ -154,19 +147,12 @@ static void css_power_down_common(const psci_power_state_t *target_state)
        /* Prevent interrupts from spuriously waking up this cpu */
        arm_gic_cpuif_deactivate();
 
-       if (PLAT_MAX_PWR_LVL > ARM_PWR_LVL1) {
-               /*
-                * Check if power down at system power domain level is
-                * requested.
-                */
-               if (target_state->pwr_domain_state[ARM_PWR_LVL2] ==
-                                                       ARM_LOCAL_STATE_OFF)
+       /* Check if power down at system power domain level is requested */
+       if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
                        system_state = scpi_power_retention;
-       }
 
        /* Cluster is to be turned off, so disable coherency */
-       if (target_state->pwr_domain_state[ARM_PWR_LVL1] ==
-                                               ARM_LOCAL_STATE_OFF) {
+       if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
                cci_disable_snoop_dvm_reqs(MPIDR_AFFLVL1_VAL(read_mpidr()));
                cluster_state = scpi_power_off;
        }
@@ -187,9 +173,7 @@ static void css_power_down_common(const psci_power_state_t *target_state)
  ******************************************************************************/
 void css_pwr_domain_off(const psci_power_state_t *target_state)
 {
-       assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-                                               ARM_LOCAL_STATE_OFF);
-
+       assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
        css_power_down_common(target_state);
 }
 
@@ -200,16 +184,13 @@ void css_pwr_domain_off(const psci_power_state_t *target_state)
 void css_pwr_domain_suspend(const psci_power_state_t *target_state)
 {
        /*
-        * Juno has retention only at cpu level. Just return
+        * CSS currently supports retention only at cpu level. Just return
         * as nothing is to be done for retention.
         */
-       if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-                                               ARM_LOCAL_STATE_RET)
+       if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
                return;
 
-       assert(target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-                                               ARM_LOCAL_STATE_OFF);
-
+       assert(CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF);
        css_power_down_common(target_state);
 }
 
@@ -223,14 +204,18 @@ void css_pwr_domain_suspend(const psci_power_state_t *target_state)
 void css_pwr_domain_suspend_finish(
                                const psci_power_state_t *target_state)
 {
-       /*
-        * Return as nothing is to be done on waking up from retention.
-        */
-       if (target_state->pwr_domain_state[ARM_PWR_LVL0] ==
-                                               ARM_LOCAL_STATE_RET)
+       /* Return as nothing is to be done on waking up from retention. */
+       if (CSS_CORE_PWR_STATE(target_state) == ARM_LOCAL_STATE_RET)
                return;
 
-       css_pwr_domain_on_finish(target_state);
+       /* Perform system domain restore if woken up from system suspend */
+       if (CSS_SYSTEM_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF)
+               arm_system_pwr_domain_resume();
+       else
+               /* Enable the gic cpu interface */
+               arm_gic_cpuif_setup();
+
+       css_pwr_domain_on_finisher_common(target_state);
 }
 
 /*******************************************************************************
diff --git a/plat/common/plat_gicv2.c b/plat/common/plat_gicv2.c
new file mode 100644 (file)
index 0000000..65f89dc
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <gic_common.h>
+#include <gicv2.h>
+#include <interrupt_mgmt.h>
+
+/*
+ * The following platform GIC functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_get_pending_interrupt_type
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_get_interrupt_type
+#pragma weak plat_ic_end_of_interrupt
+#pragma weak plat_interrupt_type_to_line
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller
+ */
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+       unsigned int id;
+
+       id = gicv2_get_pending_interrupt_id();
+       if (id == GIC_SPURIOUS_INTERRUPT)
+               return INTR_ID_UNAVAILABLE;
+
+       return id;
+}
+
+/*
+ * This function returns the type of the highest priority pending interrupt
+ * at the Interrupt controller. In the case of GICv2, the Highest Priority
+ * Pending interrupt register (`GICC_HPPIR`) is read to determine the id of
+ * the pending interrupt. The type of interrupt depends upon the id value
+ * as follows.
+ *   1. id < PENDING_G1_INTID (1022) is reported as a S-EL1 interrupt
+ *   2. id = PENDING_G1_INTID (1022) is reported as a Non-secure interrupt.
+ *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
+ *           type.
+ */
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+       unsigned int id;
+
+       id = gicv2_get_pending_interrupt_type();
+
+       /* Assume that all secure interrupts are S-EL1 interrupts */
+       if (id < PENDING_G1_INTID)
+               return INTR_TYPE_S_EL1;
+
+       if (id == GIC_SPURIOUS_INTERRUPT)
+               return INTR_TYPE_INVAL;
+
+       return INTR_TYPE_NS;
+}
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller and indicates to the Interrupt controller
+ * that the interrupt processing has started.
+ */
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+       return gicv2_acknowledge_interrupt();
+}
+
+/*
+ * This function returns the type of the interrupt `id`, depending on how
+ * the interrupt has been configured in the interrupt controller
+ */
+uint32_t plat_ic_get_interrupt_type(uint32_t id)
+{
+       unsigned int type;
+
+       type = gicv2_get_interrupt_group(id);
+
+       /* Assume that all secure interrupts are S-EL1 interrupts */
+       return (type) ? INTR_TYPE_NS : INTR_TYPE_S_EL1;
+}
+
+/*
+ * This functions is used to indicate to the interrupt controller that
+ * the processing of the interrupt corresponding to the `id` has
+ * finished.
+ */
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+       gicv2_end_of_interrupt(id);
+}
+
+/*
+ * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
+ * The interrupt controller knows which pin/line it uses to signal a type of
+ * interrupt. It lets the interrupt management framework determine
+ * for a type of interrupt and security state, which line should be used in the
+ * SCR_EL3 to control its routing to EL3. The interrupt line is represented
+ * as the bit position of the IRQ or FIQ bit in the SCR_EL3.
+ */
+uint32_t plat_interrupt_type_to_line(uint32_t type,
+                               uint32_t security_state)
+{
+       assert(type == INTR_TYPE_S_EL1 ||
+                      type == INTR_TYPE_EL3 ||
+                      type == INTR_TYPE_NS);
+
+       /* Non-secure interrupts are signaled on the IRQ line always */
+       if (type == INTR_TYPE_NS)
+               return __builtin_ctz(SCR_IRQ_BIT);
+
+       /*
+        * Secure interrupts are signaled using the IRQ line if the FIQ is
+        * not enabled else they are signaled using the FIQ line.
+        */
+       return ((gicv2_is_fiq_enabled()) ? __builtin_ctz(SCR_FIQ_BIT) :
+                                               __builtin_ctz(SCR_IRQ_BIT));
+}
diff --git a/plat/common/plat_gicv3.c b/plat/common/plat_gicv3.c
new file mode 100644 (file)
index 0000000..249caf8
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ *
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of ARM nor the names of its contributors may be used
+ * to endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <arch_helpers.h>
+#include <assert.h>
+#include <bl_common.h>
+#include <cassert.h>
+#include <gic_common.h>
+#include <gicv3.h>
+#include <interrupt_mgmt.h>
+#include <platform.h>
+
+#if IMAGE_BL31
+
+/*
+ * The following platform GIC functions are weakly defined. They
+ * provide typical implementations that may be re-used by multiple
+ * platforms but may also be overridden by a platform if required.
+ */
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_get_pending_interrupt_type
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_get_interrupt_type
+#pragma weak plat_ic_end_of_interrupt
+#pragma weak plat_interrupt_type_to_line
+
+CASSERT((INTR_TYPE_S_EL1 == INTR_GROUP1S) &&
+       (INTR_TYPE_NS == INTR_GROUP1NS) &&
+       (INTR_TYPE_EL3 == INTR_GROUP0), assert_interrupt_type_mismatch);
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller
+ */
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+       unsigned int irqnr;
+
+       assert(IS_IN_EL3());
+       irqnr = gicv3_get_pending_interrupt_id();
+       return (gicv3_is_intr_id_special_identifier(irqnr)) ?
+                               INTR_ID_UNAVAILABLE : irqnr;
+}
+
+/*
+ * This function returns the type of the highest priority pending interrupt
+ * at the Interrupt controller. In the case of GICv3, the Highest Priority
+ * Pending interrupt system register (`ICC_HPPIR0_EL1`) is read to determine
+ * the id of the pending interrupt. The type of interrupt depends upon the
+ * id value as follows.
+ *   1. id = PENDING_G1S_INTID (1020) is reported as a S-EL1 interrupt
+ *   2. id = PENDING_G1NS_INTID (1021) is reported as a Non-secure interrupt.
+ *   3. id = GIC_SPURIOUS_INTERRUPT (1023) is reported as an invalid interrupt
+ *           type.
+ *   4. All other interrupt id's are reported as EL3 interrupt.
+ */
+uint32_t plat_ic_get_pending_interrupt_type(void)
+{
+       unsigned int irqnr;
+
+       assert(IS_IN_EL3());
+       irqnr = gicv3_get_pending_interrupt_type();
+
+       switch (irqnr) {
+       case PENDING_G1S_INTID:
+               return INTR_TYPE_S_EL1;
+       case PENDING_G1NS_INTID:
+               return INTR_TYPE_NS;
+       case GIC_SPURIOUS_INTERRUPT:
+               return INTR_TYPE_INVAL;
+       default:
+               return INTR_TYPE_EL3;
+       }
+}
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller and indicates to the Interrupt controller
+ * that the interrupt processing has started.
+ */
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+       assert(IS_IN_EL3());
+       return gicv3_acknowledge_interrupt();
+}
+
+/*
+ * This function returns the type of the interrupt `id`, depending on how
+ * the interrupt has been configured in the interrupt controller
+ */
+uint32_t plat_ic_get_interrupt_type(uint32_t id)
+{
+       assert(IS_IN_EL3());
+       return gicv3_get_interrupt_type(id, plat_my_core_pos());
+}
+
+/*
+ * This functions is used to indicate to the interrupt controller that
+ * the processing of the interrupt corresponding to the `id` has
+ * finished.
+ */
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+       assert(IS_IN_EL3());
+       gicv3_end_of_interrupt(id);
+}
+
+/*
+ * An ARM processor signals interrupt exceptions through the IRQ and FIQ pins.
+ * The interrupt controller knows which pin/line it uses to signal a type of
+ * interrupt. It lets the interrupt management framework determine for a type of
+ * interrupt and security state, which line should be used in the SCR_EL3 to
+ * control its routing to EL3. The interrupt line is represented as the bit
+ * position of the IRQ or FIQ bit in the SCR_EL3.
+ */
+uint32_t plat_interrupt_type_to_line(uint32_t type,
+                               uint32_t security_state)
+{
+       assert(type == INTR_TYPE_S_EL1 ||
+              type == INTR_TYPE_EL3 ||
+              type == INTR_TYPE_NS);
+
+       assert(sec_state_is_valid(security_state));
+       assert(IS_IN_EL3());
+
+       switch (type) {
+       case INTR_TYPE_S_EL1:
+               /*
+                * The S-EL1 interrupts are signaled as IRQ in S-EL0/1 contexts
+                * and as FIQ in the NS-EL0/1/2 contexts
+                */
+               if (security_state == SECURE)
+                       return __builtin_ctz(SCR_IRQ_BIT);
+               else
+                       return __builtin_ctz(SCR_FIQ_BIT);
+       case INTR_TYPE_NS:
+               /*
+                * The Non secure interrupts will be signaled as FIQ in S-EL0/1
+                * contexts and as IRQ in the NS-EL0/1/2 contexts.
+                */
+               if (security_state == SECURE)
+                       return __builtin_ctz(SCR_FIQ_BIT);
+               else
+                       return __builtin_ctz(SCR_IRQ_BIT);
+       default:
+               assert(0);
+               /* Fall through in the release build */
+       case INTR_TYPE_EL3:
+               /*
+                * The EL3 interrupts are signaled as FIQ in both S-EL0/1 and
+                * NS-EL0/1/2 contexts
+                */
+               return __builtin_ctz(SCR_FIQ_BIT);
+       }
+}
+#endif
+#if IMAGE_BL32
+
+#pragma weak plat_ic_get_pending_interrupt_id
+#pragma weak plat_ic_acknowledge_interrupt
+#pragma weak plat_ic_end_of_interrupt
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller
+ */
+uint32_t plat_ic_get_pending_interrupt_id(void)
+{
+       unsigned int irqnr;
+
+       assert(IS_IN_EL1());
+       irqnr = gicv3_get_pending_interrupt_id_sel1();
+       return (irqnr == GIC_SPURIOUS_INTERRUPT) ?
+                               INTR_ID_UNAVAILABLE : irqnr;
+}
+
+/*
+ * This function returns the highest priority pending interrupt at
+ * the Interrupt controller and indicates to the Interrupt controller
+ * that the interrupt processing has started.
+ */
+uint32_t plat_ic_acknowledge_interrupt(void)
+{
+       assert(IS_IN_EL1());
+       return gicv3_acknowledge_interrupt_sel1();
+}
+
+/*
+ * This functions is used to indicate to the interrupt controller that
+ * the processing of the interrupt corresponding to the `id` has
+ * finished.
+ */
+void plat_ic_end_of_interrupt(uint32_t id)
+{
+       assert(IS_IN_EL1());
+       gicv3_end_of_interrupt_sel1(id);
+}
+#endif