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 <asm/nios2.h> 12 #include <asm/types.h> 13 #include <asm/io.h> 14 #include <asm/ptrace.h> 15 #include <common.h> 16 #include <command.h> 17 #include <watchdog.h> 18 #ifdef CONFIG_STATUS_LED 19 #include <status_led.h> 20 #endif 21 22 struct nios_timer { 23 u32 status; /* Timer status reg */ 24 u32 control; /* Timer control reg */ 25 u32 periodl; /* Timeout period low */ 26 u32 periodh; /* Timeout period high */ 27 u32 snapl; /* Snapshot low */ 28 u32 snaph; /* Snapshot high */ 29 }; 30 31 /* status register */ 32 #define NIOS_TIMER_TO (1 << 0) /* Timeout */ 33 #define NIOS_TIMER_RUN (1 << 1) /* Timer running */ 34 35 /* control register */ 36 #define NIOS_TIMER_ITO (1 << 0) /* Timeout int ena */ 37 #define NIOS_TIMER_CONT (1 << 1) /* Continuous mode */ 38 #define NIOS_TIMER_START (1 << 2) /* Start timer */ 39 #define NIOS_TIMER_STOP (1 << 3) /* Stop timer */ 40 41 #if defined(CONFIG_SYS_TIMER_BASE) && !defined(CONFIG_SYS_TIMER_IRQ) 42 #error CONFIG_SYS_TIMER_IRQ not defined (see documentation) 43 #endif 44 45 /****************************************************************************/ 46 47 struct irq_action { 48 interrupt_handler_t *handler; 49 void *arg; 50 int count; 51 }; 52 53 static struct irq_action vecs[32]; 54 55 /*************************************************************************/ 56 static volatile ulong timestamp; 57 58 /* 59 * The board must handle this interrupt if a timer is not 60 * provided. 61 */ 62 void tmr_isr (void *arg) 63 { 64 struct nios_timer *tmr = (struct nios_timer *)arg; 65 /* Interrupt is cleared by writing anything to the 66 * status register. 67 */ 68 writel (0, &tmr->status); 69 timestamp += CONFIG_SYS_NIOS_TMRMS; 70 #ifdef CONFIG_STATUS_LED 71 status_led_tick(timestamp); 72 #endif 73 } 74 75 unsigned long notrace timer_read_counter(void) 76 { 77 struct nios_timer *tmr = (struct nios_timer *)CONFIG_SYS_TIMER_BASE; 78 u32 val; 79 80 /* Trigger update */ 81 writel(0x0, &tmr->snapl); 82 83 /* Read timer value */ 84 val = readl(&tmr->snapl) & 0xffff; 85 val |= (readl(&tmr->snaph) & 0xffff) << 16; 86 87 return ~val; 88 } 89 90 int timer_init(void) 91 { 92 struct nios_timer *tmr = (struct nios_timer *)CONFIG_SYS_TIMER_BASE; 93 94 writel (0, &tmr->status); 95 writel (0, &tmr->control); 96 writel (NIOS_TIMER_STOP, &tmr->control); 97 98 writel (0xffff, &tmr->periodl); 99 writel (0xffff, &tmr->periodh); 100 101 writel (NIOS_TIMER_CONT | NIOS_TIMER_START, &tmr->control); 102 /* FIXME */ 103 irq_install_handler(CONFIG_SYS_TIMER_IRQ, tmr_isr, (void *)tmr); 104 105 return 0; 106 } 107 108 /*************************************************************************/ 109 int disable_interrupts (void) 110 { 111 int val = rdctl (CTL_STATUS); 112 wrctl (CTL_STATUS, val & ~STATUS_IE); 113 return (val & STATUS_IE); 114 } 115 116 void enable_interrupts( void ) 117 { 118 int val = rdctl (CTL_STATUS); 119 wrctl (CTL_STATUS, val | STATUS_IE); 120 } 121 122 void external_interrupt (struct pt_regs *regs) 123 { 124 unsigned irqs; 125 struct irq_action *act; 126 127 /* Evaluate only irqs that are both enabled AND pending */ 128 irqs = rdctl (CTL_IENABLE) & rdctl (CTL_IPENDING); 129 act = vecs; 130 131 /* Assume (as does the Nios2 HAL) that bit 0 is highest 132 * priority. NOTE: There is ALWAYS a handler assigned 133 * (the default if no other). 134 */ 135 while (irqs) { 136 if (irqs & 1) { 137 act->handler (act->arg); 138 act->count++; 139 } 140 irqs >>=1; 141 act++; 142 } 143 } 144 145 static void def_hdlr (void *arg) 146 { 147 unsigned irqs = rdctl (CTL_IENABLE); 148 149 /* Disable the individual interrupt -- with gratuitous 150 * warning. 151 */ 152 irqs &= ~(1 << (int)arg); 153 wrctl (CTL_IENABLE, irqs); 154 printf ("WARNING: Disabling unhandled interrupt: %d\n", 155 (int)arg); 156 } 157 158 /*************************************************************************/ 159 void irq_install_handler (int irq, interrupt_handler_t *hdlr, void *arg) 160 { 161 162 int flag; 163 struct irq_action *act; 164 unsigned ena = rdctl (CTL_IENABLE); 165 166 if ((irq < 0) || (irq > 31)) 167 return; 168 act = &vecs[irq]; 169 170 flag = disable_interrupts (); 171 if (hdlr) { 172 act->handler = hdlr; 173 act->arg = arg; 174 ena |= (1 << irq); /* enable */ 175 } else { 176 act->handler = def_hdlr; 177 act->arg = (void *)irq; 178 ena &= ~(1 << irq); /* disable */ 179 } 180 wrctl (CTL_IENABLE, ena); 181 if (flag) enable_interrupts (); 182 } 183 184 185 int interrupt_init (void) 186 { 187 int i; 188 189 /* Assign the default handler to all */ 190 for (i = 0; i < 32; i++) { 191 vecs[i].handler = def_hdlr; 192 vecs[i].arg = (void *)i; 193 vecs[i].count = 0; 194 } 195 196 enable_interrupts (); 197 return (0); 198 } 199 200 201 /*************************************************************************/ 202 #if defined(CONFIG_CMD_IRQ) 203 int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 204 { 205 int i; 206 struct irq_action *act = vecs; 207 208 printf ("\nInterrupt-Information:\n\n"); 209 printf ("Nr Routine Arg Count\n"); 210 printf ("-----------------------------\n"); 211 212 for (i=0; i<32; i++) { 213 if (act->handler != def_hdlr) { 214 printf ("%02d %08lx %08lx %d\n", 215 i, 216 (ulong)act->handler, 217 (ulong)act->arg, 218 act->count); 219 } 220 act++; 221 } 222 printf ("\n"); 223 224 return (0); 225 } 226 #endif 227