Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ARCv2: [intc] HS38 core interrupt controller

Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Vineet Gupta <vgupta@synopsys.com>

+282
+22
Documentation/devicetree/bindings/arc/archs-intc.txt
··· 1 + * ARC-HS incore Interrupt Controller (Provided by cores implementing ARCv2 ISA) 2 + 3 + Properties: 4 + 5 + - compatible: "snps,archs-intc" 6 + - interrupt-controller: This is an interrupt controller. 7 + - #interrupt-cells: Must be <1>. 8 + 9 + Single Cell "interrupts" property of a device specifies the IRQ number 10 + between 16 to 256 11 + 12 + intc accessed via the special ARC AUX register interface, hence "reg" property 13 + is not specified. 14 + 15 + Example: 16 + 17 + intc: interrupt-controller { 18 + compatible = "snps,archs-intc"; 19 + interrupt-controller; 20 + #interrupt-cells = <1>; 21 + interrupts = <16 17 18 19 20 21 22 23 24 25>; 22 + };
+1
arch/arc/include/asm/arcregs.h
··· 31 31 #define ARC_REG_BPU_BCR 0xc0 32 32 #define ARC_REG_ISA_CFG_BCR 0xc1 33 33 #define ARC_REG_RTT_BCR 0xF2 34 + #define ARC_REG_IRQ_BCR 0xF3 34 35 #define ARC_REG_SMART_BCR 0xFF 35 36 36 37 /* status32 Bits Positions */
+116
arch/arc/include/asm/irqflags-arcv2.h
··· 1 + /* 2 + * Copyright (C) 2014-15 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + */ 8 + 9 + #ifndef __ASM_IRQFLAGS_ARCV2_H 10 + #define __ASM_IRQFLAGS_ARCV2_H 11 + 12 + #include <asm/arcregs.h> 13 + 14 + /* status32 Bits */ 15 + #define STATUS_AD_BIT 19 /* Disable Align chk: core supports non-aligned */ 16 + #define STATUS_IE_BIT 31 17 + 18 + #define STATUS_AD_MASK (1<<STATUS_AD_BIT) 19 + #define STATUS_IE_MASK (1<<STATUS_IE_BIT) 20 + 21 + #define AUX_USER_SP 0x00D 22 + #define AUX_IRQ_CTRL 0x00E 23 + #define AUX_IRQ_ACT 0x043 /* Active Intr across all levels */ 24 + #define AUX_IRQ_LVL_PEND 0x200 /* Pending Intr across all levels */ 25 + #define AUX_IRQ_PRIORITY 0x206 26 + #define ICAUSE 0x40a 27 + #define AUX_IRQ_SELECT 0x40b 28 + #define AUX_IRQ_ENABLE 0x40c 29 + 30 + /* 0 is highest level, but taken by FIRQs, if present in design */ 31 + #define ARCV2_IRQ_DEF_PRIO 0 32 + 33 + /* seed value for status register */ 34 + #define ISA_INIT_STATUS_BITS (STATUS_IE_MASK | STATUS_AD_MASK | \ 35 + (ARCV2_IRQ_DEF_PRIO << 1)) 36 + 37 + #ifndef __ASSEMBLY__ 38 + 39 + /* 40 + * Save IRQ state and disable IRQs 41 + */ 42 + static inline long arch_local_irq_save(void) 43 + { 44 + unsigned long flags; 45 + 46 + __asm__ __volatile__(" clri %0 \n" : "=r" (flags) : : "memory"); 47 + 48 + return flags; 49 + } 50 + 51 + /* 52 + * restore saved IRQ state 53 + */ 54 + static inline void arch_local_irq_restore(unsigned long flags) 55 + { 56 + __asm__ __volatile__(" seti %0 \n" : : "r" (flags) : "memory"); 57 + } 58 + 59 + /* 60 + * Unconditionally Enable IRQs 61 + */ 62 + static inline void arch_local_irq_enable(void) 63 + { 64 + __asm__ __volatile__(" seti \n" : : : "memory"); 65 + } 66 + 67 + /* 68 + * Unconditionally Disable IRQs 69 + */ 70 + static inline void arch_local_irq_disable(void) 71 + { 72 + __asm__ __volatile__(" clri \n" : : : "memory"); 73 + } 74 + 75 + /* 76 + * save IRQ state 77 + */ 78 + static inline long arch_local_save_flags(void) 79 + { 80 + unsigned long temp; 81 + 82 + __asm__ __volatile__( 83 + " lr %0, [status32] \n" 84 + : "=&r"(temp) 85 + : 86 + : "memory"); 87 + 88 + return temp; 89 + } 90 + 91 + /* 92 + * Query IRQ state 93 + */ 94 + static inline int arch_irqs_disabled_flags(unsigned long flags) 95 + { 96 + return !(flags & (STATUS_IE_MASK)); 97 + } 98 + 99 + static inline int arch_irqs_disabled(void) 100 + { 101 + return arch_irqs_disabled_flags(arch_local_save_flags()); 102 + } 103 + 104 + #else 105 + 106 + .macro IRQ_DISABLE scratch 107 + clri 108 + .endm 109 + 110 + .macro IRQ_ENABLE scratch 111 + seti 112 + .endm 113 + 114 + #endif /* __ASSEMBLY__ */ 115 + 116 + #endif
+143
arch/arc/kernel/intc-arcv2.c
··· 1 + /* 2 + * Copyright (C) 2014 Synopsys, Inc. (www.synopsys.com) 3 + * 4 + * This program is free software; you can redistribute it and/or modify 5 + * it under the terms of the GNU General Public License version 2 as 6 + * published by the Free Software Foundation. 7 + * 8 + */ 9 + 10 + #include <linux/interrupt.h> 11 + #include <linux/module.h> 12 + #include <linux/of.h> 13 + #include <linux/irqdomain.h> 14 + #include <linux/irqchip.h> 15 + #include "../../drivers/irqchip/irqchip.h" 16 + #include <asm/irq.h> 17 + 18 + /* 19 + * Early Hardware specific Interrupt setup 20 + * -Called very early (start_kernel -> setup_arch -> setup_processor) 21 + * -Platform Independent (must for any ARC Core) 22 + * -Needed for each CPU (hence not foldable into init_IRQ) 23 + */ 24 + void arc_init_IRQ(void) 25 + { 26 + unsigned int tmp; 27 + 28 + struct aux_irq_ctrl { 29 + #ifdef CONFIG_CPU_BIG_ENDIAN 30 + unsigned int res3:18, save_idx_regs:1, res2:1, 31 + save_u_to_u:1, save_lp_regs:1, save_blink:1, 32 + res:4, save_nr_gpr_pairs:5; 33 + #else 34 + unsigned int save_nr_gpr_pairs:5, res:4, 35 + save_blink:1, save_lp_regs:1, save_u_to_u:1, 36 + res2:1, save_idx_regs:1, res3:18; 37 + #endif 38 + } ictrl; 39 + 40 + *(unsigned int *)&ictrl = 0; 41 + 42 + ictrl.save_nr_gpr_pairs = 6; /* r0 to r11 (r12 saved manually) */ 43 + ictrl.save_blink = 1; 44 + ictrl.save_lp_regs = 1; /* LP_COUNT, LP_START, LP_END */ 45 + ictrl.save_u_to_u = 0; /* user ctxt saved on kernel stack */ 46 + ictrl.save_idx_regs = 1; /* JLI, LDI, EI */ 47 + 48 + WRITE_AUX(AUX_IRQ_CTRL, ictrl); 49 + 50 + /* setup status32, don't enable intr yet as kernel doesn't want */ 51 + tmp = read_aux_reg(0xa); 52 + tmp |= ISA_INIT_STATUS_BITS; 53 + tmp &= ~STATUS_IE_MASK; 54 + asm volatile("flag %0 \n"::"r"(tmp)); 55 + 56 + /* 57 + * ARCv2 core intc provides multiple interrupt priorities (upto 16). 58 + * Typical builds though have only two levels (0-high, 1-low) 59 + * Linux by default uses lower prio 1 for most irqs, reserving 0 for 60 + * NMI style interrupts in future (say perf) 61 + * 62 + * Read the intc BCR to confirm that Linux default priority is avail 63 + * in h/w 64 + * 65 + * Note: 66 + * IRQ_BCR[27..24] contains N-1 (for N priority levels) and prio level 67 + * is 0 based. 68 + */ 69 + tmp = (read_aux_reg(ARC_REG_IRQ_BCR) >> 24 ) & 0xF; 70 + if (ARCV2_IRQ_DEF_PRIO > tmp) 71 + panic("Linux default irq prio incorrect\n"); 72 + } 73 + 74 + static void arcv2_irq_mask(struct irq_data *data) 75 + { 76 + write_aux_reg(AUX_IRQ_SELECT, data->irq); 77 + write_aux_reg(AUX_IRQ_ENABLE, 0); 78 + } 79 + 80 + static void arcv2_irq_unmask(struct irq_data *data) 81 + { 82 + write_aux_reg(AUX_IRQ_SELECT, data->irq); 83 + write_aux_reg(AUX_IRQ_ENABLE, 1); 84 + } 85 + 86 + void arcv2_irq_enable(struct irq_data *data) 87 + { 88 + /* set default priority */ 89 + write_aux_reg(AUX_IRQ_SELECT, data->irq); 90 + write_aux_reg(AUX_IRQ_PRIORITY, ARCV2_IRQ_DEF_PRIO); 91 + 92 + /* 93 + * hw auto enables (linux unmask) all by default 94 + * So no need to do IRQ_ENABLE here 95 + * XXX: However OSCI LAN need it 96 + */ 97 + write_aux_reg(AUX_IRQ_ENABLE, 1); 98 + } 99 + 100 + static struct irq_chip arcv2_irq_chip = { 101 + .name = "ARCv2 core Intc", 102 + .irq_mask = arcv2_irq_mask, 103 + .irq_unmask = arcv2_irq_unmask, 104 + .irq_enable = arcv2_irq_enable 105 + }; 106 + 107 + static int arcv2_irq_map(struct irq_domain *d, unsigned int irq, 108 + irq_hw_number_t hw) 109 + { 110 + if (irq == TIMER0_IRQ) 111 + irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_percpu_irq); 112 + else 113 + irq_set_chip_and_handler(irq, &arcv2_irq_chip, handle_level_irq); 114 + 115 + return 0; 116 + } 117 + 118 + static const struct irq_domain_ops arcv2_irq_ops = { 119 + .xlate = irq_domain_xlate_onecell, 120 + .map = arcv2_irq_map, 121 + }; 122 + 123 + static struct irq_domain *root_domain; 124 + 125 + static int __init 126 + init_onchip_IRQ(struct device_node *intc, struct device_node *parent) 127 + { 128 + if (parent) 129 + panic("DeviceTree incore intc not a root irq controller\n"); 130 + 131 + root_domain = irq_domain_add_legacy(intc, NR_CPU_IRQS, 0, 0, 132 + &arcv2_irq_ops, NULL); 133 + 134 + if (!root_domain) 135 + panic("root irq domain not avail\n"); 136 + 137 + /* with this we don't need to export root_domain */ 138 + irq_set_default_host(root_domain); 139 + 140 + return 0; 141 + } 142 + 143 + IRQCHIP_DECLARE(arc_intc, "snps,archs-intc", init_onchip_IRQ);