From 41b3af52b7264237b9c1f3645618b4d35285a927 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Sun, 13 Mar 2016 10:12:45 -0600 Subject: [PATCH] i.MX6: Revamp GIC initialization logic; add missing register bit definitions and initialization of GIC control register for secure cases --- arch/arm/src/armv7-a/arm_gic.c | 332 ++++++++++++++++++++------------ arch/arm/src/armv7-a/gic.h | 59 +++++- arch/arm/src/imx6/imx_cpuinit.c | 4 +- arch/arm/src/imx6/imx_iomuxc.c | 2 +- arch/arm/src/imx6/imx_irq.c | 3 +- 5 files changed, 271 insertions(+), 129 deletions(-) diff --git a/arch/arm/src/armv7-a/arm_gic.c b/arch/arm/src/armv7-a/arm_gic.c index 0c40ca8898..eeb1ccd22f 100644 --- a/arch/arm/src/armv7-a/arm_gic.c +++ b/arch/arm/src/armv7-a/arm_gic.c @@ -58,11 +58,105 @@ * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: arm_gic_nlines + * + * Description: + * Return the number of interrupt lines supported by this GIC + * implementation (include both PPIs (32) and SPIs). + * + * Input Parameters: + * None + * + * Returned Value: + * The number of interrupt lines. + * + ****************************************************************************/ + +static inline unsigned int arm_gic_nlines(void) +{ + uint32_t regval; + uint32_t field; + + /* Get the number of interrupt lines. */ + + regval = getreg32(GIC_ICDICTR); + field = (regval & GIC_ICDICTR_ITLINES_MASK) >> GIC_ICDICTR_ITLINES_SHIFT; + return (field + 1) << 5; +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: arm_gic0_initialize + * + * Description: + * Perform common, one-time GIC initialization on CPU0 only. Both + * arm_gic0_initialize() must be called on CPU0; arm_gic_initialize() must + * be called for all CPUs. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void arm_gic0_initialize(void) +{ + unsigned int nlines = arm_gic_nlines(); + unsigned int irq; + + /* Initialize SPIs. The following should be done only by CPU0. */ + + /* A processor in Secure State sets: + * + * 1. Which interrupts are non-secure (ICDISR). + * REVISIT: Which bit state corresponds to secure? + * 2. Trigger mode of the SPI (ICDICFR). All fields set to 11->Edge + * sensitive. + * 3. Innterrupt Clear-Enable (ICDICER) + * 3. Priority of the SPI using the priority set register (ICDIPR). + * Priority values are 8-bit unsigned binary. A GIC supports a + * minimum of 16 and a maximum of 256 priority levels. Here all + * are set to the middle priority 128 (0x80). + * 4. Target that receives the SPI interrupt (ICDIPTR). Set all to + * CPU0. + */ + + /* Registers with 1-bit per interrupt */ + + for (irq = GIC_IRQ_SPI; irq < nlines; irq += 32) + { + putreg32(0x00000000, GIC_ICDISR(irq)); /* SPIs secure */ + putreg32(0xffffffff, GIC_ICDICFR(irq)); /* SPIs edge triggered */ + putreg32(0xffffffff, GIC_ICDICER(irq)); /* SPIs disabled */ + } + + /* Registers with 8-bits per interrupt */ + + for (irq = GIC_IRQ_SPI; irq < nlines; irq += 8) + { + putreg32(0x80808080, GIC_ICDIPR(irq)); /* SPI priority */ + putreg32(0x01010101, GIC_ICDIPTR(irq)); /* SPI on CPU0 */ + } + +#ifdef CONFIG_SMP + /* Attach SGI interrupt handlers */ + + DEBUGVERIFY(irq_attach(GIC_IRQ_SGI1, arm_start_handler)); + DEBUGVERIFY(irq_attach(GIC_IRQ_SGI2, arm_pause_handler)); +#endif +} + /**************************************************************************** * Name: arm_gic_initialize * * Description: - * Perform basic GIC initialization for the current CPU + * Perform common GIC initialization for the current CPU (all CPUs) * * Input Parameters: * None @@ -74,71 +168,9 @@ void arm_gic_initialize(void) { - unsigned int nlines; - unsigned int irq; - uint32_t regval; - uint32_t field; -#ifdef CONFIG_SMP - int cpu; + uint32_t iccicr; - /* Which CPU are we initializing */ - - cpu = up_cpu_index(); -#endif - - /* Get the number of interrupt lines. */ - - regval = getreg32(GIC_ICDICTR); - field = (regval & GIC_ICDICTR_ITLINES_MASK) >> GIC_ICDICTR_ITLINES_SHIFT; - nlines = (field + 1) << 5; - - /* Initialize SPIs. The following should be done only by CPU0. */ - -#ifdef CONFIG_SMP - if (cpu == 0) -#endif - { - /* A processor in Secure State sets: - * - * 1. Which interrupts are non-secure (ICDISR). - * REVISIT: Which bit state corresponds to secure? - * 2. Trigger mode of the SPI (ICDICFR). All fields set to 11->Edge - * sensitive. - * 3. Innterrupt Clear-Enable (ICDICER) - * 3. Priority of the SPI using the priority set register (ICDIPR). - * Priority values are 8-bit unsigned binary. A GIC supports a - * minimum of 16 and a maximum of 256 priority levels. Here all - * are set to the middle priority 128 (0x80). - * 4. Target that receives the SPI interrupt (ICDIPTR). Set all to - * CPU0. - */ - - /* Registers with 1-bit per interrupt */ - - for (irq = GIC_IRQ_SPI; irq < nlines; irq += 32) - { - putreg32(0x00000000, GIC_ICDISR(irq)); /* SPIs secure */ - putreg32(0xffffffff, GIC_ICDICFR(irq)); /* SPIs edge triggered */ - putreg32(0xffffffff, GIC_ICDICER(irq)); /* SPIs disabled */ - } - - /* Registers with 8-bits per interrupt */ - - for (irq = GIC_IRQ_SPI; irq < nlines; irq += 8) - { - putreg32(0x80808080, GIC_ICDIPR(irq)); /* SPI priority */ - putreg32(0x01010101, GIC_ICDIPTR(irq)); /* SPI on CPU0 */ - } - -#ifdef CONFIG_SMP - /* Attach SGI interrupt handlers */ - - DEBUGVERIFY(irq_attach(GIC_IRQ_SGI1, arm_start_handler)); - DEBUGVERIFY(irq_attach(GIC_IRQ_SGI2, arm_pause_handler)); -#endif - } - - /* The remaining steps need to be done by all CPUs */ + /* Initialize PPIs. The following steps need to be done by all CPUs */ /* Initialize SGIs and PPIs. NOTE: A processor in non-secure state cannot * program its interrupt security registers and must get a secure processor @@ -159,53 +191,6 @@ void arm_gic_initialize(void) putreg32(0x80000000, GIC_ICDIPR(24)); /* PPI[0] priority */ putreg32(0x80808080, GIC_ICDIPR(28)); /* PPI[1:4] priority */ -#if defined(CONFIG_ARCH_TRUSTZONE_SECURE) || defined(CONFIG_ARCH_TRUSTZONE_BOTH) - /* Set FIQn=1 if secure interrupts are to signal using nfiq_c. - * - * NOTE: Only for processors that operate in secure state. - * REVISIT: Do I need to do this? - */ - -#endif - -#ifdef CONFIG_ARCH_TRUSTZONE_BOTH - /* Program the AckCtl bit to select the required interrupt acknowledge - * behavior. - * - * NOTE: Only for processors that operate in both secure and non-secure - * state. - */ - -# warning Missing logic - - /* Program the SBPR bit to select the required binary pointer behavior. - * - * NOTE: Only for processors that operate in both secure and non-secure - * state. - */ - -# warning Missing logic -#endif - -#if defined(CONFIG_ARCH_TRUSTZONE_SECURE) || defined(CONFIG_ARCH_TRUSTZONE_BOTH) - /* Set EnableS=1 to enable CPU interface to signal secure interrupts. - * - * NOTE: Only for processors that operate in secure mostatede. - */ - -# warning Missing logic -#endif - -#if defined(CONFIG_ARCH_TRUSTZONE_NONSECURE) || defined(CONFIG_ARCH_TRUSTZONE_BOTH) - /* Set EnableNS=1 to enable the CPU to signal non-secure interrupts. - * - * NOTE: Only for processors that operate in non-secure state. - * REVISIT: Initial implementation operates only in secure state. - */ - -# warning Missing logic -#endif - /* Set the binary point register. * * Priority values are 8-bit unsigned binary. The binary point is a 3-bit @@ -219,7 +204,89 @@ void arm_gic_initialize(void) putreg32(GIC_ICCBPR_NOPREMPT, GIC_ICCBPR); -#ifdef CONFIG_ARCH_TRUSTZONE_BOTH + /* Program the idle priority in the PMR */ + + putreg32(GIC_ICCPMR_MASK, GIC_ICCPMR); + + /* Configure the CPU Interface Control Register */ + + iccicr = getreg32(GIC_ICCICR); + +#if defined(CONFIG_ARCH_TRUSTZONE_SECURE) || defined(CONFIG_ARCH_TRUSTZONE_BOTH) + /* Clear secure state ICCICR bits to be configured below */ + + iccicr &= ~(GIC_ICCICRS_FIQEN | GIC_ICCICRS_ACKTCTL | GIC_ICCICRS_CBPR | + GIC_ICCICRS_EOIMODES | GIC_ICCICRS_EOIMODENS | + GIC_ICCICRS_ENABLEGRP0 | GIC_ICCICRS_ENABLEGRP1 | + GIC_ICCICRS_FIQBYPDISGRP0 | GIC_ICCICRS_IRQBYPDISGRP0 | + GIC_ICCICRS_FIQBYPDISGRP1 | GIC_ICCICRS_IRQBYPDISGRP1); + +#elif defined(CONFIG_ARCH_TRUSTZONE_NONSECURE) + /* Clear non-secure state ICCICR bits to be configured below */ + + iccicr &= ~(GIC_ICCICRS_EOIMODENS | GIC_ICCICRU_ENABLEGRP1 | + GIC_ICCICRU_FIQBYPDISGRP1 |GIC_ICCICRU_IRQBYPDISGRP1); + +#endif + +#if defined(CONFIG_ARCH_TRUSTZONE_SECURE) || defined(CONFIG_ARCH_TRUSTZONE_BOTH) + /* Set FIQn=1 if secure interrupts are to signal using nfiq_c. + * + * NOTE: Only for processors that operate in secure state. + * REVISIT: Do I need to do this? + */ + + iccicr |= GIC_ICCICRS_FIQEN; +#endif + +#if defined(ONFIG_ARCH_TRUSTZONE_BOTH) + /* Program the AckCtl bit to select the required interrupt acknowledge + * behavior. + * + * NOTE: Only for processors that operate in both secure and non-secure + * state. + * REVISIT: I don't yet fully understand this setting. + */ + + // iccicr |= GIC_ICCICRS_ACKTCTL; + + /* Program the SBPR bit to select the required binary pointer behavior. + * + * NOTE: Only for processors that operate in both secure and non-secure + * state. + * REVISIT: I don't yet fully understand this setting. + */ + + // iccicr |= GIC_ICCICRS_CBPR; +#endif + +#if defined(CONFIG_ARCH_TRUSTZONE_SECURE) || defined(CONFIG_ARCH_TRUSTZONE_BOTH) + /* Set EnableS=1 to enable CPU interface to signal secure interrupts. + * + * NOTE: Only for processors that operate in secure state. + */ + + iccicr |= GIC_ICCICRS_EOIMODES; +#endif + +#if defined(CONFIG_ARCH_TRUSTZONE_NONSECURE) + /* Set EnableNS=1 to enable the CPU to signal non-secure interrupts. + * + * NOTE: Only for processors that operate in non-secure state. + */ + + iccicr |= GIC_ICCICRS_EOIMODENS; + +#elif defined(CONFIG_ARCH_TRUSTZONE_BOTH) + /* Set EnableNS=1 to enable the CPU to signal non-secure interrupts. + * + * NOTE: Only for processors that operate in non-secure state. + */ + + iccicr |= GIC_ICCICRU_EOIMODENS; +#endif + + #ifdef CONFIG_ARCH_TRUSTZONE_BOTH /* If the processor operates in both security states and SBPR=0, then it * must switch to the other security state and repeat the programming of * the binary point register so that the binary point will be programmed @@ -229,10 +296,41 @@ void arm_gic_initialize(void) # warning Missing logic #endif +#if !defined(CONFIG_ARCH_HAVE_TRUSTZONE) /* Enable the distributor by setting the the Enable bit in the enable - * register. + * register (no security extensions). */ + iccicr |= GIC_ICCICR_ENABLE; + +#elif defined(CONFIG_ARCH_TRUSTZONE_SECURE) + /* Enable the Group 0 interrupts, FIQEn and disable Group 0/1 + * bypass. + */ + + iccicr |= (GIC_ICCICRS_ENABLEGRP0 | GIC_ICCICRS_FIQBYPDISGRP0 | + GIC_ICCICRS_IRQBYPDISGRP0 | GIC_ICCICRS_FIQBYPDISGRP1 | + GIC_ICCICRS_IRQBYPDISGRP1); + +#elif defined(CONFIG_ARCH_TRUSTZONE_BOTH) + /* Enable the Group 0/1 interrupts, FIQEn and disable Group 0/1 + * bypass. + */ + + iccicr |= (GIC_ICCICRS_ENABLEGRP0 | GIC_ICCICRS_ENABLEGRP1 | + GIC_ICCICRS_FIQBYPDISGRP0 | GIC_ICCICRS_IRQBYPDISGRP0 | + GIC_ICCICRS_FIQBYPDISGRP1 | GIC_ICCICRS_IRQBYPDISGRP1); + +#else /* defined(CONFIG_ARCH_TRUSTZONE_NONSECURE) */ + /* Enable the Group 1 interrupts and disable Group 1 bypass. */ + + iccicr |= (GIC_ICCICRU_ENABLEGRP1 | GIC_ICCICRU_FIQBYPDISGRP1 | + GIC_ICCICRU_IRQBYPDISGRP1); + +#endif + + /* Write the final ICCICR value */ + putreg32(GIC_ICCICR_ENABLE, GIC_ICCICR); #ifdef CONFIG_ARCH_TRUSTZONE_BOTH @@ -275,7 +373,7 @@ uint32_t *arm_decodeirq(uint32_t *regs) * interrupt. */ - DEBUGASSERT(irg < NR_IRQS || irq == 1023); + DEBUGASSERT(irq < NR_IRQS || irq == 1023); if (irq < NR_IRQS) { /* Dispatch the interrupt */ @@ -416,7 +514,7 @@ int up_prioritize_irq(int irq, int priority) * cpuset - The set of CPUs to receive the SGI * * Returned Value: - * OK is always retured at present. + * OK is always returned at present. * ****************************************************************************/ @@ -424,8 +522,6 @@ int arm_cpu_sgi(int sgi, unsigned int cpuset) { uint32_t regval; - DEBUGASSERT(cpu >= 0 && cpu < CONFIG_SMP_NCPUS); - #ifdef CONFIG_SMP regval = GIC_ICDSGIR_INTID(sgi) | GIC_ICDSGIR_CPUTARGET(cpuset) | GIC_ICDSGIR_TGTFILTER_LIST; diff --git a/arch/arm/src/armv7-a/gic.h b/arch/arm/src/armv7-a/gic.h index cfa48aec32..03dca452ca 100644 --- a/arch/arm/src/armv7-a/gic.h +++ b/arch/arm/src/armv7-a/gic.h @@ -225,17 +225,42 @@ /* GIC Register Bit Definitions *********************************************/ /* Interrupt Interface registers */ -/* CPU Interface Control Register */ +/* CPU Interface Control Register -- without security extensions */ -#define GIC_ICCICR_ENABLE (1 << 0) /* Bit 0: Enable the CPU interface for this GIC */ +#define GIC_ICCICR_ENABLE (1 << 0) /* Bit 0: Enable the CPU interface for this GIC */ /* Bits 1-31: Reserved */ -/* Interrupt Priority Mask Register */ - /* Bits 0-3: Reserved */ -#define GIC_ICCPMR_SHIFT (4) /* Bits 4-7: Priority mask */ -#define GIC_ICCPMR_MASK (15 << GIC_ICCPMR_SHIFT) +/* CPU Interface Control Register -- with security extensions, non-secure copy */ + +#define GIC_ICCICRU_ENABLEGRP1 (1 << 0) /* Bit 0: Enable Group 1 interrupts for the CPU */ + /* Bits 1-4: Reserved */ +#define GIC_ICCICRU_FIQBYPDISGRP1 (1 << 5) /* Bit 5: FIQ disabled for CPU Group 1*/ +#define GIC_ICCICRU_IRQBYPDISGRP1 (1 << 6) /* Bit 6: IRQ disabled for CPU Group 1*/ + /* Bits 7-8: Reserved */ +#define GIC_ICCICRU_EOIMODENS (1 << 9) /* Bit 6: Control EIOIR access (non-secure) */ + /* Bits 10-31: Reserved */ +/* CPU Interface Control Register -- with security extensions, secure copy */ + +#define GIC_ICCICRS_ENABLEGRP0 (1 << 0) /* Bit 0: Enable Group 0 interrupts for the CPU */ +#define GIC_ICCICRS_ENABLEGRP1 (1 << 1) /* Bit 1: Enable Group 1 interrupts for the CPU */ +#define GIC_ICCICRS_ACKTCTL (1 << 2) /* Bit 2: Group 1 interrupt activation control */ +#define GIC_ICCICRS_FIQEN (1 << 3) /* Bit 3: Signal Group 0 via FIQ */ +#define GIC_ICCICRS_CBPR (1 << 4) /* Bit 4: Control Group 0/1 Pre-emption */ +#define GIC_ICCICRS_FIQBYPDISGRP0 (1 << 5) /* Bit 5: FIQ disabled for CPU Group 0 */ +#define GIC_ICCICRS_IRQBYPDISGRP0 (1 << 6) /* Bit 6: IRQ disabled for CPU Group 0 */ +#define GIC_ICCICRS_FIQBYPDISGRP1 (1 << 7) /* Bit 5: FIQ disabled for CPU Group 1 */ +#define GIC_ICCICRS_IRQBYPDISGRP1 (1 << 8) /* Bit 6: IRQ disabled for CPU Group 1 */ +#define GIC_ICCICRS_EOIMODES (1 << 9) /* Bit 6: Control EIOIR access (secure) */ +#define GIC_ICCICRS_EOIMODENS (1 << 10) /* Bit 10: Control EIOIR access (non-secure) */ + /* Bits 11-31: Reserved */ +/* Interrupt Priority Mask Register. Priority values are 8-bit unsigned + * binary. A GIC supports a minimum of 16 and a maximum of 256 priority + * levels. As a result, PMR settings make sense. + */ + +#define GIC_ICCPMR_SHIFT (0) /* Bits 0-7: Priority mask */ +#define GIC_ICCPMR_MASK (0xff << GIC_ICCPMR_SHIFT) # define GIC_ICCPMR_VALUE(n) ((uint32_t)(n) << GIC_ICCPMR_SHIFT) /* Bits 8-31: Reserved */ - /* Binary point Register and Aliased Non-secure Binary Point Register. * Priority values are 8-bit unsigned binary. A GIC supports a minimum of * 16 and a maximum of 256 priority levels. As a result, not all binary @@ -483,11 +508,29 @@ extern "C" #define EXTERN extern #endif +/**************************************************************************** + * Name: arm_gic0_initialize + * + * Description: + * Perform common, one-time GIC initialization on CPU0 only. Both + * arm_gic0_initialize() must be called on CPU0; arm_gic_initialize() must + * be called for all CPUs. + * + * Input Parameters: + * None + * + * Returned Value: + * None + * + ****************************************************************************/ + +void arm_gic0_initialize(void); + /**************************************************************************** * Name: arm_gic_initialize * * Description: - * Perform basic GIC initialization for the current CPU + * Perform common GIC initialization for the current CPU (all CPUs) * * Input Parameters: * None diff --git a/arch/arm/src/imx6/imx_cpuinit.c b/arch/arm/src/imx6/imx_cpuinit.c index 3c5f76114c..d928781408 100644 --- a/arch/arm/src/imx6/imx_cpuinit.c +++ b/arch/arm/src/imx6/imx_cpuinit.c @@ -69,8 +69,10 @@ int up_cpu_initialize(void) { - /* Initialize the Generic Interrupt Controller (GIC) for CPU0 */ + /* Initialize the Generic Interrupt Controller (GIC) for CPUn (n != 0) */ arm_gic_initialize(); return OK; } + +#endif /* CONFIG_SMP */ diff --git a/arch/arm/src/imx6/imx_iomuxc.c b/arch/arm/src/imx6/imx_iomuxc.c index e56a6faed5..563086f381 100644 --- a/arch/arm/src/imx6/imx_iomuxc.c +++ b/arch/arm/src/imx6/imx_iomuxc.c @@ -348,7 +348,7 @@ static const uint8_t g_mux2ctl_map[IMX_PADMUX_NREGISTERS] = unsigned int imx_padmux_map(unsigned int padmux) { - DEBUGASSERT(padmx < IMX_PADMUX_NREGISTERS); + DEBUGASSERT(padmux < IMX_PADMUX_NREGISTERS); return (unsigned int)g_mux2ctl_map[padmux]; } diff --git a/arch/arm/src/imx6/imx_irq.c b/arch/arm/src/imx6/imx_irq.c index 0098419cb7..e00a8e9527 100644 --- a/arch/arm/src/imx6/imx_irq.c +++ b/arch/arm/src/imx6/imx_irq.c @@ -105,7 +105,8 @@ void up_irqinitialize(void) /* Initialize the Generic Interrupt Controller (GIC) for CPU0 */ - arm_gic_initialize(); + arm_gic0_initialize(); /* Initialization unique to CPU0 */ + arm_gic_initialize(); /* Initialization common to all CPUs */ #ifdef CONFIG_ARCH_LOWVECTORS /* If CONFIG_ARCH_LOWVECTORS is defined, then the vectors located at the