From ad92c1981f81fe28b901894db537a0c98d5956e5 Mon Sep 17 00:00:00 2001 From: Vernon Mauery Date: Wed, 14 Nov 2018 10:21:40 -0800 Subject: [PATCH] Add Aspeed g5 interrupt support This adds a few new files to the board g5 directory. Several Intel features require interrupts running in U-Boot, so this adds basic interrupt registration and handling support. Signed-off-by: Vernon Mauery Change-Id: Id7072f1408dcf364968b1b74f2192e50a22a82f0 --- Kconfig | 13 ++ arch/arm/lib/interrupts.c | 11 ++ board/aspeed/ast-g5/Makefile | 3 +- board/aspeed/ast-g5/ast-g5-irq.c | 176 ++++++++++++++++++++++++++++ board/aspeed/ast-g5/ast-g5-irq.h | 39 ++++++ board/aspeed/ast-g5/ast-g5.c | 3 + board/aspeed/ast-g5/ast-g5.h | 7 ++ cmd/Kconfig | 5 + configs/ast_g5_ncsi_2boot_defconfig | 1 + configs/ast_g5_ncsi_defconfig | 1 + configs/ast_g5_phy_defconfig | 1 + 11 files changed, 259 insertions(+), 1 deletion(-) create mode 100644 board/aspeed/ast-g5/ast-g5-irq.c create mode 100644 board/aspeed/ast-g5/ast-g5-irq.h create mode 100644 board/aspeed/ast-g5/ast-g5.h diff --git a/Kconfig b/Kconfig index 3ceff25032..d6439d01ca 100644 --- a/Kconfig +++ b/Kconfig @@ -115,6 +115,19 @@ if EXPERT When disabling this, please check if malloc calls, maybe should be replaced by calloc - if one expects zeroed memory. endif + +config USE_IRQ + bool "Use interrupts" + default n + +config STACKSIZE_IRQ + int "Size for IRQ stack (only if USE_IRQ enabled)" + default 16384 + +config STACKSIZE_FIQ + int "Size for FIQ stack (only if USE_IRQ enabled)" + default 16384 + endmenu # General setup menu "Boot images" diff --git a/arch/arm/lib/interrupts.c b/arch/arm/lib/interrupts.c index ed83043abb..a96b3aa070 100644 --- a/arch/arm/lib/interrupts.c +++ b/arch/arm/lib/interrupts.c @@ -94,6 +94,17 @@ int disable_interrupts (void) : "memory"); return (old & 0x80) == 0; } + +int global_interrupts_enabled(void) +{ + unsigned long old; + __asm__ __volatile__("mrs %0, cpsr\n" + : "=r" (old) + : + : "memory"); + return (old & 0x80) == 0; +} + #else int interrupt_init (void) { diff --git a/board/aspeed/ast-g5/Makefile b/board/aspeed/ast-g5/Makefile index d1d7f8525e..df4e63966e 100644 --- a/board/aspeed/ast-g5/Makefile +++ b/board/aspeed/ast-g5/Makefile @@ -1 +1,2 @@ -obj-y = ast-g5.o +obj-y += ast-g5.o +obj-y += ast-g5-irq.o diff --git a/board/aspeed/ast-g5/ast-g5-irq.c b/board/aspeed/ast-g5/ast-g5-irq.c new file mode 100644 index 0000000000..860f16cf05 --- /dev/null +++ b/board/aspeed/ast-g5/ast-g5-irq.c @@ -0,0 +1,176 @@ +/* + * Copyright 2018 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#include +#include + +#include +#include +#include + +#include "ast-g5.h" +#include "ast-g5-irq.h" + +DECLARE_GLOBAL_DATA_PTR; + +#ifdef CONFIG_USE_IRQ + +#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) + +int arch_interrupt_init_early(void) +{ + writel(VIC_CLEAR_ALL, AST_VIC_BASE + VIC_ENABLE_CLEAR_L); + writel(VIC_CLEAR_ALL, AST_VIC_BASE + VIC_ENABLE_CLEAR_H); + return 0; +} +int arch_interrupt_init(void) +{ + return 0; +} + +#define AST_IRQ_START_L 0 +#define AST_IRQ_END_L 31 +#define AST_IRQ_START_H 32 +#define AST_IRQ_END_H 63 +#define AST_IRQ_COUNT 64 +static interrupt_handler_t *handlers[AST_IRQ_COUNT] = {NULL}; +static unsigned long irq_total = 0; +static unsigned long irq_counts[AST_IRQ_COUNT] = {0}; + +int request_irq(int irq, interrupt_handler_t *handler) +{ + if (irq < AST_IRQ_START_L || irq > AST_IRQ_END_H) { + printf("irq %d out of range\n", irq); + return -1; + } + if (handlers[irq]) { + printf("irq %d already in use (%p)\n", irq, handlers[irq]); + return -1; + } + handlers[irq] = handler; + if (irq < AST_IRQ_START_H) { + writel((1 << irq), AST_VIC_BASE + VIC_ENABLE_L); + } else { + writel((1 << (irq - AST_IRQ_START_H)), + AST_VIC_BASE + VIC_ENABLE_H); + } + return 0; +} + +int release_irq(int irq) +{ + if (irq < AST_IRQ_START_L || irq > AST_IRQ_END_H) { + return -1; + } + if (handlers[irq]) { + handlers[irq] = NULL; + if (irq < AST_IRQ_START_H) { + writel((1 << irq), AST_VIC_BASE + VIC_ENABLE_CLEAR_L); + } else { + writel((1 << (irq - AST_IRQ_START_H)), + AST_VIC_BASE + VIC_ENABLE_CLEAR_H); + } + } + return 0; +} + +extern int global_interrupts_enabled(void); +int do_irqinfo(cmd_tbl_t *cmdtp, int flag, int argc, char *const argv[]) +{ + int i; + int enabled = global_interrupts_enabled(); + unsigned long long irqs_enabled = + ((unsigned long long)readl(AST_VIC_BASE + VIC_ENABLE_H)) + << AST_IRQ_START_H + | readl(AST_VIC_BASE + VIC_ENABLE_L); + printf("interrupts %sabled\n", (enabled ? "en" : "dis")); + for (i = AST_IRQ_START_L; i < AST_IRQ_COUNT; i++) { + printf("% 2i (% 3s): %lu\n", i, + ((irqs_enabled & 1) ? "on" : "off"), irq_counts[i]); + irqs_enabled >>= 1; + } + printf("total: %lu\n", irq_total); + return 0; +} + +void do_irq(struct pt_regs *pt_regs) +{ + uint32_t irq = readl(AST_VIC_BASE + VIC_STATUS_L); + int i; + irq_total++; + if (irq) { + // handler irq0-31 + for (i = AST_IRQ_START_L; i <= AST_IRQ_END_L; i++) { + if (irq & (1 << i)) { + irq_counts[i]++; + /* mask */ + writel((1 << i), + AST_VIC_BASE + VIC_ENABLE_CLEAR_L); + if (handlers[i]) { + handlers[i](pt_regs); + /* clear */ + writel((1 << i), + AST_VIC_BASE + + VIC_INTERRUPT_CLEAR_L); + /* unmask */ + writel((1 << i), + AST_VIC_BASE + VIC_ENABLE_L); + } else { + printf("unexpected interrupt %i; masking\n", + i); + /* clear; do not unmask */ + writel((1 << i), + AST_VIC_BASE + + VIC_INTERRUPT_CLEAR_L); + } + } + } + } + irq = readl(AST_VIC_BASE + VIC_STATUS_H); + if (irq) { + // handler irq32-63 + for (i = AST_IRQ_START_H; i <= AST_IRQ_END_H; i++) { + if (irq & (1 << (i - AST_IRQ_START_H))) { + irq_counts[i]++; + /* mask */ + writel((1 << (i - AST_IRQ_START_H)), + AST_VIC_BASE + VIC_ENABLE_CLEAR_H); + if (handlers[i]) { + handlers[i](pt_regs); + /* clear */ + writel((1 << (i - AST_IRQ_START_H)), + AST_VIC_BASE + + VIC_INTERRUPT_CLEAR_H); + /* unmask */ + writel((1 << (i - AST_IRQ_START_H)), + AST_VIC_BASE + VIC_ENABLE_H); + } else { + printf("unexpected interrupt %i; masking\n", + i); + /* clear; do not unmask */ + writel((1 << (i - AST_IRQ_START_H)), + AST_VIC_BASE + + VIC_INTERRUPT_CLEAR_H); + } + } + } + } +} +#endif diff --git a/board/aspeed/ast-g5/ast-g5-irq.h b/board/aspeed/ast-g5/ast-g5-irq.h new file mode 100644 index 0000000000..703eeabf13 --- /dev/null +++ b/board/aspeed/ast-g5/ast-g5-irq.h @@ -0,0 +1,39 @@ +/* + * Copyright 2018 Intel Corporation + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ + +#ifndef __AST_G5_IRQ_H__ +#define __AST_G5_IRQ_H__ + +#include + +#ifdef CONFIG_USE_IRQ + +int arch_interrupt_init_early(void); + +int request_irq(int irq, interrupt_handler_t *handler); + +int release_irq(int irq); + +#else /* CONFIG_USE_IRQ */ + +int arch_interrupt_init_early(void) { + return 0; +} + +int request_irq(int irq, interrupt_handler_t *handler) { + return -1; +} + +int release_irq(int irq) { + return -1; +} + +#endif /* CONFIG_USE_IRQ */ + +#endif /* __AST_G5_IRQ_H__ */ diff --git a/board/aspeed/ast-g5/ast-g5.c b/board/aspeed/ast-g5/ast-g5.c index 02eb2c3990..ca25348178 100644 --- a/board/aspeed/ast-g5/ast-g5.c +++ b/board/aspeed/ast-g5/ast-g5.c @@ -17,6 +17,8 @@ #include #include +#include "ast-g5.h" + DECLARE_GLOBAL_DATA_PTR; int board_early_init_f(void) @@ -25,6 +27,7 @@ int board_early_init_f(void) ast_config_uart5_clk(); /*enable pass through*/ ast_enable_pass_through(); + arch_interrupt_init_early(); return 0; } diff --git a/board/aspeed/ast-g5/ast-g5.h b/board/aspeed/ast-g5/ast-g5.h new file mode 100644 index 0000000000..9fd10eccb3 --- /dev/null +++ b/board/aspeed/ast-g5/ast-g5.h @@ -0,0 +1,7 @@ +#ifndef _AST_G5_H_ +#define _AST_G5_H_ + +#include +#include "ast-g5-irq.h" + +#endif /* _AST_G5_H_ */ diff --git a/cmd/Kconfig b/cmd/Kconfig index d69b817c82..33be2407d2 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -313,6 +313,11 @@ endmenu menu "Device access commands" +config CMD_IRQ + bool "interrupts - enable/disable interrupts" + depends on USE_IRQ + default y + config CMD_DM bool "dm - Access to driver model information" depends on DM diff --git a/configs/ast_g5_ncsi_2boot_defconfig b/configs/ast_g5_ncsi_2boot_defconfig index 2d28c86966..d5b7894a9e 100644 --- a/configs/ast_g5_ncsi_2boot_defconfig +++ b/configs/ast_g5_ncsi_2boot_defconfig @@ -33,3 +33,4 @@ CONFIG_CMD_CRC32=y CONFIG_LOOPW=y CONFIG_CMD_MEMTEST=y CONFIG_CMD_MX_CYCLIC=y +CONFIG_USE_IRQ=y diff --git a/configs/ast_g5_ncsi_defconfig b/configs/ast_g5_ncsi_defconfig index 74029ed514..9481e5fb6e 100644 --- a/configs/ast_g5_ncsi_defconfig +++ b/configs/ast_g5_ncsi_defconfig @@ -11,3 +11,4 @@ CONFIG_HUSH_PARSER=y CONFIG_OF_LIBFDT=y CONFIG_SPI_FLASH=y CONFIG_SYS_NS16550=y +CONFIG_USE_IRQ=y diff --git a/configs/ast_g5_phy_defconfig b/configs/ast_g5_phy_defconfig index 767f3af605..4aefcf49e8 100644 --- a/configs/ast_g5_phy_defconfig +++ b/configs/ast_g5_phy_defconfig @@ -12,3 +12,4 @@ CONFIG_HUSH_PARSER=y CONFIG_OF_LIBFDT=y CONFIG_SPI_FLASH=y CONFIG_SYS_NS16550=y +CONFIG_USE_IRQ=y