137e4dafaSPeter Tyser /* 237e4dafaSPeter Tyser * (C) Copyright 2000-2002 337e4dafaSPeter Tyser * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 437e4dafaSPeter Tyser * 537e4dafaSPeter Tyser * (C) Copyright 2004, Psyent Corporation <www.psyent.com> 637e4dafaSPeter Tyser * Scott McNutt <smcnutt@psyent.com> 737e4dafaSPeter Tyser * 81a459660SWolfgang Denk * SPDX-License-Identifier: GPL-2.0+ 937e4dafaSPeter Tyser */ 1037e4dafaSPeter Tyser 1157cfeb51SThomas Chou #include <asm/nios2.h> 1237e4dafaSPeter Tyser #include <asm/types.h> 1337e4dafaSPeter Tyser #include <asm/io.h> 1437e4dafaSPeter Tyser #include <asm/ptrace.h> 1537e4dafaSPeter Tyser #include <common.h> 1637e4dafaSPeter Tyser #include <command.h> 1737e4dafaSPeter Tyser 18*e6500f86SThomas Chou /*************************************************************************/ 1937e4dafaSPeter Tyser struct irq_action { 2037e4dafaSPeter Tyser interrupt_handler_t *handler; 2137e4dafaSPeter Tyser void *arg; 2237e4dafaSPeter Tyser int count; 2337e4dafaSPeter Tyser }; 2437e4dafaSPeter Tyser 2537e4dafaSPeter Tyser static struct irq_action vecs[32]; 2637e4dafaSPeter Tyser 2737e4dafaSPeter Tyser int disable_interrupts (void) 2837e4dafaSPeter Tyser { 2937e4dafaSPeter Tyser int val = rdctl (CTL_STATUS); 3037e4dafaSPeter Tyser wrctl (CTL_STATUS, val & ~STATUS_IE); 3137e4dafaSPeter Tyser return (val & STATUS_IE); 3237e4dafaSPeter Tyser } 3337e4dafaSPeter Tyser 3437e4dafaSPeter Tyser void enable_interrupts( void ) 3537e4dafaSPeter Tyser { 3637e4dafaSPeter Tyser int val = rdctl (CTL_STATUS); 3737e4dafaSPeter Tyser wrctl (CTL_STATUS, val | STATUS_IE); 3837e4dafaSPeter Tyser } 3937e4dafaSPeter Tyser 4037e4dafaSPeter Tyser void external_interrupt (struct pt_regs *regs) 4137e4dafaSPeter Tyser { 4237e4dafaSPeter Tyser unsigned irqs; 4337e4dafaSPeter Tyser struct irq_action *act; 4437e4dafaSPeter Tyser 4537e4dafaSPeter Tyser /* Evaluate only irqs that are both enabled AND pending */ 4637e4dafaSPeter Tyser irqs = rdctl (CTL_IENABLE) & rdctl (CTL_IPENDING); 4737e4dafaSPeter Tyser act = vecs; 4837e4dafaSPeter Tyser 4937e4dafaSPeter Tyser /* Assume (as does the Nios2 HAL) that bit 0 is highest 5037e4dafaSPeter Tyser * priority. NOTE: There is ALWAYS a handler assigned 5137e4dafaSPeter Tyser * (the default if no other). 5237e4dafaSPeter Tyser */ 5337e4dafaSPeter Tyser while (irqs) { 5437e4dafaSPeter Tyser if (irqs & 1) { 5537e4dafaSPeter Tyser act->handler (act->arg); 5637e4dafaSPeter Tyser act->count++; 5737e4dafaSPeter Tyser } 5837e4dafaSPeter Tyser irqs >>=1; 5937e4dafaSPeter Tyser act++; 6037e4dafaSPeter Tyser } 6137e4dafaSPeter Tyser } 6237e4dafaSPeter Tyser 6337e4dafaSPeter Tyser static void def_hdlr (void *arg) 6437e4dafaSPeter Tyser { 6537e4dafaSPeter Tyser unsigned irqs = rdctl (CTL_IENABLE); 6637e4dafaSPeter Tyser 6737e4dafaSPeter Tyser /* Disable the individual interrupt -- with gratuitous 6837e4dafaSPeter Tyser * warning. 6937e4dafaSPeter Tyser */ 7037e4dafaSPeter Tyser irqs &= ~(1 << (int)arg); 7137e4dafaSPeter Tyser wrctl (CTL_IENABLE, irqs); 7237e4dafaSPeter Tyser printf ("WARNING: Disabling unhandled interrupt: %d\n", 7337e4dafaSPeter Tyser (int)arg); 7437e4dafaSPeter Tyser } 7537e4dafaSPeter Tyser 7637e4dafaSPeter Tyser /*************************************************************************/ 7737e4dafaSPeter Tyser void irq_install_handler (int irq, interrupt_handler_t *hdlr, void *arg) 7837e4dafaSPeter Tyser { 7937e4dafaSPeter Tyser 8037e4dafaSPeter Tyser int flag; 8137e4dafaSPeter Tyser struct irq_action *act; 8237e4dafaSPeter Tyser unsigned ena = rdctl (CTL_IENABLE); 8337e4dafaSPeter Tyser 8437e4dafaSPeter Tyser if ((irq < 0) || (irq > 31)) 8537e4dafaSPeter Tyser return; 8637e4dafaSPeter Tyser act = &vecs[irq]; 8737e4dafaSPeter Tyser 8837e4dafaSPeter Tyser flag = disable_interrupts (); 8937e4dafaSPeter Tyser if (hdlr) { 9037e4dafaSPeter Tyser act->handler = hdlr; 9137e4dafaSPeter Tyser act->arg = arg; 9237e4dafaSPeter Tyser ena |= (1 << irq); /* enable */ 9337e4dafaSPeter Tyser } else { 9437e4dafaSPeter Tyser act->handler = def_hdlr; 9537e4dafaSPeter Tyser act->arg = (void *)irq; 9637e4dafaSPeter Tyser ena &= ~(1 << irq); /* disable */ 9737e4dafaSPeter Tyser } 9837e4dafaSPeter Tyser wrctl (CTL_IENABLE, ena); 9937e4dafaSPeter Tyser if (flag) enable_interrupts (); 10037e4dafaSPeter Tyser } 10137e4dafaSPeter Tyser 10237e4dafaSPeter Tyser 10337e4dafaSPeter Tyser int interrupt_init (void) 10437e4dafaSPeter Tyser { 10537e4dafaSPeter Tyser int i; 10637e4dafaSPeter Tyser 10737e4dafaSPeter Tyser /* Assign the default handler to all */ 10837e4dafaSPeter Tyser for (i = 0; i < 32; i++) { 10937e4dafaSPeter Tyser vecs[i].handler = def_hdlr; 11037e4dafaSPeter Tyser vecs[i].arg = (void *)i; 11137e4dafaSPeter Tyser vecs[i].count = 0; 11237e4dafaSPeter Tyser } 11337e4dafaSPeter Tyser 11437e4dafaSPeter Tyser enable_interrupts (); 11537e4dafaSPeter Tyser return (0); 11637e4dafaSPeter Tyser } 11737e4dafaSPeter Tyser 11837e4dafaSPeter Tyser 11937e4dafaSPeter Tyser /*************************************************************************/ 12037e4dafaSPeter Tyser #if defined(CONFIG_CMD_IRQ) 12154841ab5SWolfgang Denk int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 12237e4dafaSPeter Tyser { 12337e4dafaSPeter Tyser int i; 12437e4dafaSPeter Tyser struct irq_action *act = vecs; 12537e4dafaSPeter Tyser 12637e4dafaSPeter Tyser printf ("\nInterrupt-Information:\n\n"); 12737e4dafaSPeter Tyser printf ("Nr Routine Arg Count\n"); 12837e4dafaSPeter Tyser printf ("-----------------------------\n"); 12937e4dafaSPeter Tyser 13037e4dafaSPeter Tyser for (i=0; i<32; i++) { 13137e4dafaSPeter Tyser if (act->handler != def_hdlr) { 13237e4dafaSPeter Tyser printf ("%02d %08lx %08lx %d\n", 13337e4dafaSPeter Tyser i, 13437e4dafaSPeter Tyser (ulong)act->handler, 13537e4dafaSPeter Tyser (ulong)act->arg, 13637e4dafaSPeter Tyser act->count); 13737e4dafaSPeter Tyser } 13837e4dafaSPeter Tyser act++; 13937e4dafaSPeter Tyser } 14037e4dafaSPeter Tyser printf ("\n"); 14137e4dafaSPeter Tyser 14237e4dafaSPeter Tyser return (0); 14337e4dafaSPeter Tyser } 14437e4dafaSPeter Tyser #endif 145