From 959b75b846aa25168fe9e3d04ceb0e0778f89992 Mon Sep 17 00:00:00 2001 From: Kuiying Wang Date: Fri, 3 Jan 2020 12:52:29 +0800 Subject: [PATCH] Enable interrupt in u-boot. Ast2600 is Cortex-A7 GIC V2 is used as the interrupt controller GIC includes GICD and GICC Testedby: 1. Enable interrupt based SW handshake for ESPI 2. Both ArcherCity and Ast2600 EVB are working well. Signed-off-by: Kuiying Wang --- arch/arm/lib/vectors.S | 31 ++++++- board/aspeed/ast2600_intel/ast-irq.c | 154 +++++++++++++++++------------------ configs/evb-ast2600_defconfig | 1 + include/configs/evb_ast2600.h | 1 + 4 files changed, 107 insertions(+), 80 deletions(-) diff --git a/arch/arm/lib/vectors.S b/arch/arm/lib/vectors.S index 2ca6e2494a7a..e2ed04a204de 100644 --- a/arch/arm/lib/vectors.S +++ b/arch/arm/lib/vectors.S @@ -13,7 +13,7 @@ */ #include - +#define CONFIG_USE_IRQ /* * A macro to allow insertion of an ARM exception vector either * for the non-boot0 case or by a boot0-header. @@ -145,6 +145,17 @@ fiq: #else /* !CONFIG_SPL_BUILD */ +#ifdef CONFIG_USE_IRQ +/* IRQ stack memory (calculated at run-time) */ +.globl IRQ_STACK_START +IRQ_STACK_START: + .word 0x0badc0de +/* IRQ stack memory (calculated at run-time) */ +.globl FIQ_STACK_START +FIQ_STACK_START: + .word 0x0badc0de +#endif + /* IRQ stack memory (calculated at run-time) + 8 bytes */ .globl IRQ_STACK_START_IN IRQ_STACK_START_IN: @@ -277,17 +288,31 @@ not_used: bad_save_user_regs bl do_not_used + .align 5 +#ifdef CONFIG_USE_IRQ +irq: + get_irq_stack + irq_save_user_regs + bl do_irq + irq_restore_user_regs + .align 5 +fiq: + get_fiq_stack + /* someone ought to write a more effective fiq_save_user_regs */ + irq_save_user_regs + bl do_fiq + irq_restore_user_regs .align 5 +#else irq: get_bad_stack bad_save_user_regs bl do_irq - .align 5 fiq: get_bad_stack bad_save_user_regs bl do_fiq - +#endif /* CONFIG_USE_IRQ */ #endif /* CONFIG_SPL_BUILD */ diff --git a/board/aspeed/ast2600_intel/ast-irq.c b/board/aspeed/ast2600_intel/ast-irq.c index f817f8cd7c81..6e91b17ab186 100644 --- a/board/aspeed/ast2600_intel/ast-irq.c +++ b/board/aspeed/ast2600_intel/ast-irq.c @@ -18,19 +18,6 @@ DECLARE_GLOBAL_DATA_PTR; #define GIC_INTERFACE_OFFSET 0x4000 #define GIC_VIRT_OFFSET 0x6000 -#define VIC_STATUS_L 0x80 -#define VIC_STATUS_H 0x84 -#define VIC_IRQ_SELECTION_L 0x98 -#define VIC_IRQ_SELECTION_H 0x9C -#define VIC_ENABLE_L 0xA0 -#define VIC_ENABLE_H 0xA4 -#define VIC_ENABLE_CLEAR_L 0xA8 -#define VIC_ENABLE_CLEAR_H 0xAC -#define VIC_INTERRUPT_CLEAR_L 0xD8 -#define VIC_INTERRUPT_CLEAR_H 0xDC - -#define VIC_CLEAR_ALL (~0) - /* GIC_DISTRIBUTOR_OFFSET register offsets */ #define GICD_CTLR 0x000 #define GICD_TYPER 0x004 @@ -82,7 +69,9 @@ DECLARE_GLOBAL_DATA_PTR; #define GICC_IIDR 0x00fc #define GICC_DIR 0x1000 -#define GIC_CPU_IMPLEMENTER_MAGIC 0x0102143b +#define GIC_CPU_IMPLEMENTER_MAGIC 0x0102143b +#define GICC_IAR_INT_ID_MASK 0x3ff +#define GIC_CPU_DEACTIVATE 0x1000 /* GIC_INTERFACE_OFFSET register offsets */ #define GICH_HCR 0x000 @@ -116,9 +105,10 @@ DECLARE_GLOBAL_DATA_PTR; #define GIC_VIRT_CPU_IMPLEMENTER_MAGIC 0x0102143b -#define GICD_CTLR_ENABLE 0x03 - -#define GICD_INT_DEF_PRI 0xa0 +#define GICD_CTLR_ENABLE 0x03 /*enable group 0 and 1*/ +#define GICC_CTLR_ENABLE 0x03 +#define GICD_ITARGET_ALL 0xffffffff +#define GICD_INT_DEF_PRI 0xa0 #define GICD_INT_DEF_PRI_X4 (\ (GICD_INT_DEF_PRI << 24) |\ (GICD_INT_DEF_PRI << 16) |\ @@ -129,20 +119,30 @@ DECLARE_GLOBAL_DATA_PTR; #define GICD_INT_EN_CLR_X32 0xffffffff #define GICD_INT_EN_CLR_PPI 0xffff0000 #define GICD_INT_EN_SET_SGI 0x0000ffff +#define GICD_ICFG_LEVEL_TRIGGER 0x55555555 +#define GICC_UNMASK_ALL_PRIORITY 0xff #define gicd_readl(OFFSET) readl(gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET)) #define gicd_writel(VALUE, OFFSET) \ writel((VALUE), gbase + GIC_DISTRIBUTOR_OFFSET + (OFFSET)) #define gicc_readl(OFFSET) readl(gbase + GIC_CPU_OFFSET + (OFFSET)) +#define gicc_writel(VALUE, OFFSET) \ + writel((VALUE), gbase + GIC_CPU_OFFSET + (OFFSET)) #define gich_readl(OFFSET) readl(gbase + GIC_INTERFACE_OFFSET + (OFFSET)) #define gicv_readl(OFFSET) readl(gbase + GIC_VIRT_OFFSET + (OFFSET)) - -static size_t max_irq = 0; - #define ITLINES_MASK 0x1f #define ITLINES_SHIFT 5 - #define GIC_MAX_IRQ 1020 +#define SPI_INT_NUM_MIN 32 +#define MAX_IRQ 0xfffffffe +#define DEBUG_IRQ_ENABLED 0 +#if DEBUG_IRQ_ENABLED +#define DBG_IRQ printf +#else +#define DBG_IRQ(...) +#endif + +static size_t max_irq = 0; static interrupt_handler_t *handlers[GIC_MAX_IRQ] = {NULL}; static unsigned long irq_total = 0; static unsigned long irq_counts[GIC_MAX_IRQ] = {0}; @@ -159,31 +159,40 @@ static inline uint32_t gic_base(void) static void enable_gic(void) { - uint32_t gicd_ctlr; + uint32_t gicd_ctlr, gicc_ctlr; + DBG_IRQ(" %s()\n", __FUNCTION__); /* add GIC offset ref table 1-3 for interrupt distributor address */ gicd_ctlr = gicd_readl(GICD_CTLR); + gicc_ctlr = gicc_readl(GICC_CTLR); gicd_writel(gicd_ctlr | GICD_CTLR_ENABLE, GICD_CTLR); + gicc_writel(gicc_ctlr | GICC_CTLR_ENABLE, GICC_CTLR); } static void disable_gic(void) { - uint32_t gicd_ctlr; - + uint32_t gicd_ctlr, gicc_ctlr; + DBG_IRQ(" %s()\n", __FUNCTION__); /* add GIC offset ref table 1-3 for interrupt distributor address */ gicd_ctlr = gicd_readl(GICD_CTLR); gicd_writel(gicd_ctlr & ~GICD_CTLR_ENABLE, GICD_CTLR); + gicc_ctlr = gicc_readl(GICC_CTLR); + gicc_writel(gicc_ctlr & ~GICC_CTLR_ENABLE, GICC_CTLR); } static void enable_irq_id(unsigned int id) { + DBG_IRQ(" %s()\n", __FUNCTION__); + uint32_t grp = id >> ITLINES_SHIFT; uint32_t grp_bit = 1 << (id & ITLINES_MASK); gicd_writel(grp_bit, GICD_ISENABLERn + grp * sizeof(uint32_t)); + gicd_writel(GICD_ITARGET_ALL, GICD_ITARGETSRn + id / 4 * 4); } static void disable_irq_id(unsigned int id) { + DBG_IRQ(" %s()\n", __FUNCTION__); uint32_t grp = id >> ITLINES_SHIFT; uint32_t grp_bit = 1 << (id & ITLINES_MASK); gicd_writel(grp_bit, GICD_ICENABLERn + grp * sizeof(uint32_t)); @@ -193,22 +202,29 @@ static int gic_probe(void) { int i; gbase = gic_base(); + DBG_IRQ("gic_probe GIC base = 0x%x, magicd=0x%x\n", + gbase, gicd_readl(GICD_IIDR)); enable_gic(); if (gicd_readl(GICD_IIDR) != GIC_DISTRIBUTOR_IMPLEMENTER_MAGIC && gicc_readl(GICC_IIDR) != GIC_CPU_IMPLEMENTER_MAGIC && gicv_readl(GICV_IIDR) != GIC_VIRT_CPU_IMPLEMENTER_MAGIC) { + printf("error: magic check \n"); return 0; } /* GIC supports up to 1020 lines */ - max_irq = ((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) << ITLINES_SHIFT; + max_irq = (((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) * 32) - 1; if (max_irq > GIC_MAX_IRQ) max_irq = GIC_MAX_IRQ; /* set all lines to be level triggered N-N */ for (i = 32; i < max_irq; i += 16) - gicd_writel(0, GICD_ICFGRn + i / 4); + gicd_writel(GICD_ICFG_LEVEL_TRIGGER, GICD_ICFGRn + i / 4); + DBG_IRQ("max_irq = 0x%x, typer=0x%x, config=0x%x, maxirq=0x%x\n", max_irq, + (gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1, + gicd_readl(GICD_ICFGRn + 0x8), + ((gicd_readl(GICD_TYPER) & ITLINES_MASK) + 1) * 0x20); /* Set priority on all interrupts. */ for (i = 0; i < max_irq; i += 4) gicd_writel(GICD_INT_DEF_PRI_X4, GICD_IPRIORITYRn + i); @@ -218,9 +234,11 @@ static int gic_probe(void) gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn + i / 8); gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICENABLERn + i / 8); } - gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn); - gicd_writel(GICD_INT_EN_CLR_PPI, GICD_ICENABLERn); + gicd_writel(GICD_INT_EN_CLR_X32, GICD_ICACTIVERn); + gicd_writel(GICD_INT_EN_CLR_PPI, GICD_ICENABLERn); gicd_writel(GICD_INT_EN_SET_SGI, GICD_ISENABLERn); + /* unmask all priority */ + gicc_writel(GICC_UNMASK_ALL_PRIORITY, GICC_PMRn); return 0; } @@ -228,6 +246,7 @@ static int gic_probe(void) void irq_free_handler (int irq); static void gic_shutdown(void) { + DBG_IRQ(" %s()\n", __FUNCTION__); int i; for (i = 0; i < max_irq; i++) { @@ -238,6 +257,7 @@ static void gic_shutdown(void) int arch_interrupt_init_early(void) { + DBG_IRQ(" %s()\n", __FUNCTION__); return 0; } @@ -249,11 +269,13 @@ int arch_interrupt_init(void) handlers[i] = NULL; irq_counts[i] = 0; } + DBG_IRQ("arch_interrupt_init\n"); return gic_probe(); } int arch_interrupt_fini(void) { + DBG_IRQ(" %s()\n", __FUNCTION__); gic_shutdown(); return 0; } @@ -261,14 +283,12 @@ int arch_interrupt_fini(void) int interrupt_init (void) { /* - * setup up stacks if necessary - */ + * setup up stacks if necessary*/ + IRQ_STACK_START = gd->irq_sp + 8; IRQ_STACK_START_IN = gd->irq_sp + 8; - printf("%s()\n", __FUNCTION__); + DBG_IRQ(" %s()\n", __FUNCTION__); return arch_interrupt_init(); - - return 0; } int global_interrupts_enabled (void) @@ -286,12 +306,12 @@ void enable_interrupts (void) { unsigned long cpsr; __asm__ __volatile__("mrs %0, cpsr\n" - "bic %0, %0, #0x80\n" + "bic %0, %0, #0x1c0\n" "msr cpsr_c, %0" : "=r" (cpsr) : : "memory"); - + DBG_IRQ(" %s()\n", __FUNCTION__); return; } @@ -304,11 +324,13 @@ int disable_interrupts (void) : "=r" (cpsr), "=r" (temp) : : "memory"); + DBG_IRQ(" %s()\n", __FUNCTION__); return (cpsr & 0x80) == 0; } void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx) { + DBG_IRQ(" %s()\n", __FUNCTION__); if (irq > max_irq) { printf("irq %d out of range\n", irq); return; @@ -317,13 +339,14 @@ void irq_install_handler(int irq, interrupt_handler_t *handler, void *ctx) printf("irq %d already in use (%p)\n", irq, handlers[irq]); return; } - printf("registering handler for irq %d\n", irq); + DBG_IRQ("registering handler for irq %d\n", irq); handlers[irq] = handler; enable_irq_id(irq); } void irq_free_handler (int irq) { + DBG_IRQ(" %s()\n", __FUNCTION__); if (irq >= max_irq) { printf("irq %d out of range\n", irq); return; @@ -338,9 +361,10 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) { int i; int enabled = global_interrupts_enabled(); - printf("GIC base = 0x%x\n", gbase); - printf("interrupts %sabled\n", (enabled ? "en" : "dis")); + DBG_IRQ("GIC base = 0x%x\n", gbase); + DBG_IRQ("interrupts %sabled\n", (enabled ? "en" : "dis")); uint32_t grp_en = 0; + for (i = 0; i < max_irq; i++) { if ((i & ITLINES_MASK) == 0) grp_en = gicd_readl(GICD_ISENABLERn + @@ -348,52 +372,28 @@ int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) int irq_enabled = grp_en & (1 << (i & ITLINES_MASK)); if (!irq_enabled) continue; - printf("% 2i (% 3s): %lu\n", i, + DBG_IRQ("%2d (%3s): %lu\n", i, (irq_enabled ? "on" : "off"), irq_counts[i]); } - printf("total: %lu\n", irq_total); + DBG_IRQ("total: %lu\n", irq_total); return 0; } void do_irq(struct pt_regs *pt_regs) { - int i; - if (!gbase) { - static int printed_msg = 0; - if (!printed_msg) - { - printed_msg = 1; - printf("interrupt before configured!\n"); - } - return; - } - irq_total++; - uint32_t grp_pend = 0; - for (i = 0; i < max_irq; i++) { - /* limit reads of the pending register to once in 32 */ - if ((i & ITLINES_MASK) == 0) - grp_pend = gicd_readl(GICD_ISPENDRn + - (i >> ITLINES_SHIFT) * sizeof(uint32_t)); - uint32_t pending = grp_pend & (1 << (i & ITLINES_MASK)); - if (pending) { - irq_counts[i]++; - /* mask via GICD_ICENABLERn */ - gicd_writel(pending, GICD_ICENABLERn + - (i >> ITLINES_SHIFT) * sizeof(uint32_t)); - if (handlers[i]) { - handlers[i](pt_regs); - /* unmask via GICD_ISENABLERn */ - gicd_writel(pending, GICD_ISENABLERn + - (i >> ITLINES_SHIFT) * sizeof(uint32_t)); - /* clear pending via GICD_ICPENDRn */ - gicd_writel(pending, GICD_ICPENDRn + - (i >> ITLINES_SHIFT) * sizeof(uint32_t)); - } else { - printf("unexpected interrupt %i; masking\n", i); - /* clear pending via GICD_ICPENDRn */ - gicd_writel(pending, GICD_ISPENDRn + - (i >> ITLINES_SHIFT) * sizeof(uint32_t)); - } + uint32_t irqstat = 0, irqnr = 0; + + if (irq_total < MAX_IRQ) + irq_total++; + irqstat = gicc_readl(GICC_IAR); + irqnr = irqstat & GICC_IAR_INT_ID_MASK; + + if (irqnr > SPI_INT_NUM_MIN && irqnr < GIC_MAX_IRQ) { + gicc_writel(irqnr, GICC_EOIR); + if (irq_counts[irqnr] < MAX_IRQ) + irq_counts[irqnr]++; + if (handlers[irqnr]) { + handlers[irqnr](NULL); } } } diff --git a/configs/evb-ast2600_defconfig b/configs/evb-ast2600_defconfig index 517d59adaf11..9cd7aea98e8d 100644 --- a/configs/evb-ast2600_defconfig +++ b/configs/evb-ast2600_defconfig @@ -72,3 +72,4 @@ CONFIG_SPI=y CONFIG_DM_SPI=y CONFIG_SYSRESET=y CONFIG_WDT=y +CONFIG_USE_IRQ=y diff --git a/include/configs/evb_ast2600.h b/include/configs/evb_ast2600.h index 91a42f2522e2..15061b25d872 100644 --- a/include/configs/evb_ast2600.h +++ b/include/configs/evb_ast2600.h @@ -8,6 +8,7 @@ #include +#define CONFIG_USE_IRQ #define CONFIG_SYS_MEMTEST_START (CONFIG_SYS_SDRAM_BASE + 0x300000) #define CONFIG_SYS_MEMTEST_END (CONFIG_SYS_MEMTEST_START + 0x5000000) -- 2.7.4