diff --git a/drivers/interrupt_controller/intc_gic.c b/drivers/interrupt_controller/intc_gic.c index 9aff07d006c..241531acd24 100644 --- a/drivers/interrupt_controller/intc_gic.c +++ b/drivers/interrupt_controller/intc_gic.c @@ -11,9 +11,7 @@ * GICv3 interface is not supported. */ -#include #include -#include #include #include @@ -21,9 +19,74 @@ #error "GICv3 and above are not supported" #endif -struct gic_ictl_config { - u32_t isr_table_offset; -}; +void arm_gic_irq_enable(unsigned int irq) +{ + int int_grp, int_off; + + int_grp = irq / 32; + int_off = irq % 32; + + sys_write32((1 << int_off), (GICD_ISENABLERn + int_grp * 4)); +} + +void arm_gic_irq_disable(unsigned int irq) +{ + int int_grp, int_off; + + int_grp = irq / 32; + int_off = irq % 32; + + sys_write32((1 << int_off), (GICD_ICENABLERn + int_grp * 4)); +} + +bool arm_gic_irq_is_enabled(unsigned int irq) +{ + int int_grp, int_off; + unsigned int enabler; + + int_grp = irq / 32; + int_off = irq % 32; + + enabler = sys_read32(GICD_ISENABLERn + int_grp * 4); + + return (enabler & (1 << int_off)) != 0; +} + +void arm_gic_irq_set_priority( + unsigned int irq, unsigned int prio, u32_t flags) +{ + int int_grp, int_off; + u8_t val; + + /* Set priority */ + sys_write8(prio & 0xff, GICD_IPRIORITYRn + irq); + + /* Set interrupt type */ + int_grp = irq / 4; + int_off = (irq % 16) * 2; + + val = sys_read8(GICD_ICFGRn + int_grp); + val &= ~(GICC_ICFGR_MASK << int_off); + if (flags & IRQ_TYPE_EDGE) { + val |= (GICC_ICFGR_TYPE << int_off); + } + + sys_write8(val, GICD_ICFGRn + int_grp); +} + +unsigned int arm_gic_get_active(void) +{ + int irq; + + irq = sys_read32(GICC_IAR) & 0x3ff; + return irq; +} + +void arm_gic_eoi(unsigned int irq) +{ + /* set to inactive */ + sys_write32(irq, GICC_EOIR); +} static void gic_dist_init(void) { @@ -31,8 +94,9 @@ static void gic_dist_init(void) gic_irqs = sys_read32(GICD_TYPER) & 0x1f; gic_irqs = (gic_irqs + 1) * 32; - if (gic_irqs > 1020) + if (gic_irqs > 1020) { gic_irqs = 1020; + } /* * Disable the forwarding of pending interrupts @@ -43,22 +107,26 @@ static void gic_dist_init(void) /* * Set all global interrupts to this CPU only. */ - for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) + for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) { sys_write32(0x01010101, GICD_ITARGETSRn + i); + } /* * Set all global interrupts to be level triggered, active low. */ - for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 16) + for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 16) { sys_write32(0, GICD_ICFGRn + i / 4); + } /* Set priority on all global interrupts. */ - for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) + for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 4) { sys_write32(0, GICD_IPRIORITYRn + i); + } /* Set all interrupts to group 0 */ - for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) + for (i = GIC_SPI_INT_BASE; i < gic_irqs; i += 32) { sys_write32(0, GICD_IGROUPRn + i / 8); + } /* * Disable all interrupts. Leave the PPI and SGIs alone @@ -96,8 +164,9 @@ static void gic_cpu_init(void) /* * Set priority on PPI and SGI interrupts */ - for (i = 0; i < 32; i += 4) + for (i = 0; i < 32; i += 4) { sys_write32(0xa0a0a0a0, GICD_IPRIORITYRn + i); + } sys_write32(0xf0, GICC_PMR); @@ -112,94 +181,6 @@ static void gic_cpu_init(void) sys_write32(val, GICC_CTLR); } -static void gic_irq_enable(struct device *dev, unsigned int irq) -{ - int int_grp, int_off; - - int_grp = irq / 32; - int_off = irq % 32; - - sys_write32((1 << int_off), (GICD_ISENABLERn + int_grp * 4)); -} - -static void gic_irq_disable(struct device *dev, unsigned int irq) -{ - int int_grp, int_off; - - int_grp = irq / 32; - int_off = irq % 32; - - sys_write32((1 << int_off), (GICD_ICENABLERn + int_grp * 4)); -} - -static unsigned int gic_irq_get_state(struct device *dev) -{ - return 1; -} - -static void gic_irq_set_priority(struct device *dev, - unsigned int irq, unsigned int prio, u32_t flags) -{ - int int_grp, int_off; - u8_t val; - - /* Set priority */ - sys_write8(prio & 0xff, GICD_IPRIORITYRn + irq); - - /* Set interrupt type */ - int_grp = irq / 4; - int_off = (irq % 16) * 2; - - val = sys_read8(GICD_ICFGRn + int_grp); - val &= ~(GICC_ICFGR_MASK << int_off); - if (flags & IRQ_TYPE_EDGE) - val |= (GICC_ICFGR_TYPE << int_off); - sys_write8(val, GICD_ICFGRn + int_grp); -} - -static void gic_isr(void *arg) -{ - struct device *dev = arg; - const struct gic_ictl_config *cfg = dev->config->config_info; - void (*gic_isr_handle)(void *); - int irq, isr_offset; - - irq = sys_read32(GICC_IAR); - irq &= 0x3ff; - - if (irq == GICC_IAR_SPURIOUS) { - printk("gic: Invalid interrupt\n"); - return; - } - - isr_offset = cfg->isr_table_offset + irq; - - gic_isr_handle = _sw_isr_table[isr_offset].isr; - if (gic_isr_handle) - gic_isr_handle(_sw_isr_table[isr_offset].arg); - else - printk("gic: no handler found for int %d\n", irq); - - /* set to inactive */ - sys_write32(irq, GICC_EOIR); -} - -static int gic_init(struct device *unused); -static const struct irq_next_level_api gic_apis = { - .intr_enable = gic_irq_enable, - .intr_disable = gic_irq_disable, - .intr_get_state = gic_irq_get_state, - .intr_set_priority = gic_irq_set_priority, -}; - -static const struct gic_ictl_config gic_config = { - .isr_table_offset = CONFIG_2ND_LVL_ISR_TBL_OFFSET, -}; - -DEVICE_AND_API_INIT(arm_gic, DT_INST_0_ARM_GIC_LABEL, - gic_init, NULL, &gic_config, - PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &gic_apis); - /** * * @brief Initialize the GIC device driver @@ -210,11 +191,8 @@ DEVICE_AND_API_INIT(arm_gic, DT_INST_0_ARM_GIC_LABEL, #define GIC_PARENT_IRQ 0 #define GIC_PARENT_IRQ_PRI 0 #define GIC_PARENT_IRQ_FLAGS 0 -static int gic_init(struct device *unused) +int arm_gic_init(void) { - IRQ_CONNECT(GIC_PARENT_IRQ, GIC_PARENT_IRQ_PRI, gic_isr, - DEVICE_GET(arm_gic), GIC_PARENT_IRQ_FLAGS); - /* Init of Distributor interface registers */ gic_dist_init(); diff --git a/include/drivers/interrupt_controller/gic.h b/include/drivers/interrupt_controller/gic.h index 8cedd88a952..7d6387514e7 100644 --- a/include/drivers/interrupt_controller/gic.h +++ b/include/drivers/interrupt_controller/gic.h @@ -4,10 +4,20 @@ * SPDX-License-Identifier: Apache-2.0 */ +/** + * @file + * @brief Driver for ARM Generic Interrupt Controller + * + * The Generic Interrupt Controller (GIC) is the default interrupt controller + * for the ARM A and R profile cores. This driver is used by the ARM arch + * implementation to handle interrupts. + */ + #ifndef ZEPHYR_INCLUDE_DRIVERS_GIC_H_ #define ZEPHYR_INCLUDE_DRIVERS_GIC_H_ -#include +#include +#include /* * GIC Register Interface Base Addresses @@ -196,4 +206,65 @@ #endif /* CONFIG_GIC_VER <= 2 */ +#ifndef _ASMLANGUAGE + +/* + * GIC Driver Interface Functions + */ + +/** + * @brief Initialise ARM GIC driver + * + * @return 0 if successful + */ +int arm_gic_init(void); + +/** + * @brief Enable interrupt + * + * @param irq interrupt ID + */ +void arm_gic_irq_enable(unsigned int irq); + +/** + * @brief Disable interrupt + * + * @param irq interrupt ID + */ +void arm_gic_irq_disable(unsigned int irq); + +/** + * @brief Check if an interrupt is enabled + * + * @param irq interrupt ID + * @return Returns true if interrupt is enabled, false otherwise + */ +bool arm_gic_irq_is_enabled(unsigned int irq); + +/** + * @brief Set interrupt priority + * + * @param irq interrupt ID + * @param prio interrupt priority + * @param flags interrupt flags + */ +void arm_gic_irq_set_priority( + unsigned int irq, unsigned int prio, unsigned int flags); + +/** + * @brief Get active interrupt ID + * + * @return Returns the ID of an active interrupt + */ +unsigned int arm_gic_get_active(void); + +/** + * @brief Signal end-of-interrupt + * + * @param irq interrupt ID + */ +void arm_gic_eoi(unsigned int irq); + +#endif /* !_ASMLANGUAGE */ + #endif /* ZEPHYR_INCLUDE_DRIVERS_GIC_H_ */