1 /* 2 * (C) Copyright 2000-2002 3 * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4 * 5 * (C) Copyright 2004, Psyent Corporation <www.psyent.com> 6 * Scott McNutt <smcnutt@psyent.com> 7 * 8 * SPDX-License-Identifier: GPL-2.0+ 9 */ 10 11 #include <common.h> 12 #include <command.h> 13 #include <asm/nios2.h> 14 #include <asm/types.h> 15 #include <asm/io.h> 16 #include <asm/ptrace.h> 17 18 /*************************************************************************/ 19 struct irq_action { 20 interrupt_handler_t *handler; 21 void *arg; 22 int count; 23 }; 24 25 static struct irq_action vecs[32]; 26 27 int disable_interrupts (void) 28 { 29 int val = rdctl (CTL_STATUS); 30 wrctl (CTL_STATUS, val & ~STATUS_IE); 31 return (val & STATUS_IE); 32 } 33 34 void enable_interrupts( void ) 35 { 36 int val = rdctl (CTL_STATUS); 37 wrctl (CTL_STATUS, val | STATUS_IE); 38 } 39 40 void external_interrupt (struct pt_regs *regs) 41 { 42 unsigned irqs; 43 struct irq_action *act; 44 45 /* Evaluate only irqs that are both enabled AND pending */ 46 irqs = rdctl (CTL_IENABLE) & rdctl (CTL_IPENDING); 47 act = vecs; 48 49 /* Assume (as does the Nios2 HAL) that bit 0 is highest 50 * priority. NOTE: There is ALWAYS a handler assigned 51 * (the default if no other). 52 */ 53 while (irqs) { 54 if (irqs & 1) { 55 act->handler (act->arg); 56 act->count++; 57 } 58 irqs >>=1; 59 act++; 60 } 61 } 62 63 static void def_hdlr (void *arg) 64 { 65 unsigned irqs = rdctl (CTL_IENABLE); 66 67 /* Disable the individual interrupt -- with gratuitous 68 * warning. 69 */ 70 irqs &= ~(1 << (int)arg); 71 wrctl (CTL_IENABLE, irqs); 72 printf ("WARNING: Disabling unhandled interrupt: %d\n", 73 (int)arg); 74 } 75 76 /*************************************************************************/ 77 void irq_install_handler (int irq, interrupt_handler_t *hdlr, void *arg) 78 { 79 80 int flag; 81 struct irq_action *act; 82 unsigned ena = rdctl (CTL_IENABLE); 83 84 if ((irq < 0) || (irq > 31)) 85 return; 86 act = &vecs[irq]; 87 88 flag = disable_interrupts (); 89 if (hdlr) { 90 act->handler = hdlr; 91 act->arg = arg; 92 ena |= (1 << irq); /* enable */ 93 } else { 94 act->handler = def_hdlr; 95 act->arg = (void *)irq; 96 ena &= ~(1 << irq); /* disable */ 97 } 98 wrctl (CTL_IENABLE, ena); 99 if (flag) enable_interrupts (); 100 } 101 102 103 int interrupt_init (void) 104 { 105 int i; 106 107 /* Assign the default handler to all */ 108 for (i = 0; i < 32; i++) { 109 vecs[i].handler = def_hdlr; 110 vecs[i].arg = (void *)i; 111 vecs[i].count = 0; 112 } 113 114 enable_interrupts (); 115 return (0); 116 } 117 118 119 /*************************************************************************/ 120 #if defined(CONFIG_CMD_IRQ) 121 int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 122 { 123 int i; 124 struct irq_action *act = vecs; 125 126 printf ("\nInterrupt-Information:\n\n"); 127 printf ("Nr Routine Arg Count\n"); 128 printf ("-----------------------------\n"); 129 130 for (i=0; i<32; i++) { 131 if (act->handler != def_hdlr) { 132 printf ("%02d %08lx %08lx %d\n", 133 i, 134 (ulong)act->handler, 135 (ulong)act->arg, 136 act->count); 137 } 138 act++; 139 } 140 printf ("\n"); 141 142 return (0); 143 } 144 #endif 145