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 12 #include <nios2.h> 13 #include <nios2-io.h> 14 #include <asm/types.h> 15 #include <asm/io.h> 16 #include <asm/ptrace.h> 17 #include <common.h> 18 #include <command.h> 19 #include <watchdog.h> 20 #ifdef CONFIG_STATUS_LED 21 #include <status_led.h> 22 #endif 23 24 #if defined(CONFIG_SYS_NIOS_TMRBASE) && !defined(CONFIG_SYS_NIOS_TMRIRQ) 25 #error CONFIG_SYS_NIOS_TMRIRQ not defined (see documentation) 26 #endif 27 28 /****************************************************************************/ 29 30 struct irq_action { 31 interrupt_handler_t *handler; 32 void *arg; 33 int count; 34 }; 35 36 static struct irq_action vecs[32]; 37 38 /*************************************************************************/ 39 volatile ulong timestamp = 0; 40 41 void reset_timer (void) 42 { 43 nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE; 44 45 /* From Embedded Peripherals Handbook: 46 * 47 * "When the hardware is configured with Writeable period 48 * disabled, writing to one of the period_n registers causes 49 * the counter to reset to the fixed Timeout Period specified 50 * at system generation time." 51 * 52 * Here we force a reload to prevent early timeouts from 53 * get_timer() when the interrupt period is greater than 54 * than 1 msec. 55 * 56 * Simply write to periodl with its own value to force an 57 * internal counter reload, THEN reset the timestamp. 58 */ 59 writel (readl (&tmr->periodl), &tmr->periodl); 60 timestamp = 0; 61 62 /* From Embedded Peripherals Handbook: 63 * 64 * "Writing to one of the period_n registers stops the internal 65 * counter, except when the hardware is configured with Start/Stop 66 * control bits off. If Start/Stop control bits is off, writing 67 * either register does not stop the counter." 68 * 69 * In order to accomodate either configuration, the control 70 * register is re-written. If the counter is stopped, it will 71 * be restarted. If it is running, the write is essentially 72 * a nop. 73 */ 74 writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START, 75 &tmr->control); 76 77 } 78 79 ulong get_timer (ulong base) 80 { 81 WATCHDOG_RESET (); 82 return (timestamp - base); 83 } 84 85 /* 86 * This function is derived from Blackfin code (read timebase as long long). 87 * On Nios2 it just returns the timer value. 88 */ 89 unsigned long long get_ticks(void) 90 { 91 return get_timer(0); 92 } 93 94 /* 95 * This function is derived from Blackfin code. 96 * On Nios2 it returns the number of timer ticks per second. 97 */ 98 ulong get_tbclk(void) 99 { 100 ulong tbclk; 101 102 tbclk = CONFIG_SYS_HZ; 103 return tbclk; 104 } 105 106 /* The board must handle this interrupt if a timer is not 107 * provided. 108 */ 109 #if defined(CONFIG_SYS_NIOS_TMRBASE) 110 void tmr_isr (void *arg) 111 { 112 nios_timer_t *tmr = (nios_timer_t *)arg; 113 /* Interrupt is cleared by writing anything to the 114 * status register. 115 */ 116 writel (0, &tmr->status); 117 timestamp += CONFIG_SYS_NIOS_TMRMS; 118 #ifdef CONFIG_STATUS_LED 119 status_led_tick(timestamp); 120 #endif 121 } 122 123 static void tmr_init (void) 124 { 125 nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE; 126 127 writel (0, &tmr->status); 128 writel (0, &tmr->control); 129 writel (NIOS_TIMER_STOP, &tmr->control); 130 131 #if defined(CONFIG_SYS_NIOS_TMRCNT) 132 writel (CONFIG_SYS_NIOS_TMRCNT & 0xffff, &tmr->periodl); 133 writel ((CONFIG_SYS_NIOS_TMRCNT >> 16) & 0xffff, &tmr->periodh); 134 #endif 135 writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START, 136 &tmr->control); 137 irq_install_handler (CONFIG_SYS_NIOS_TMRIRQ, tmr_isr, (void *)tmr); 138 } 139 140 #endif /* CONFIG_SYS_NIOS_TMRBASE */ 141 142 /*************************************************************************/ 143 int disable_interrupts (void) 144 { 145 int val = rdctl (CTL_STATUS); 146 wrctl (CTL_STATUS, val & ~STATUS_IE); 147 return (val & STATUS_IE); 148 } 149 150 void enable_interrupts( void ) 151 { 152 int val = rdctl (CTL_STATUS); 153 wrctl (CTL_STATUS, val | STATUS_IE); 154 } 155 156 void external_interrupt (struct pt_regs *regs) 157 { 158 unsigned irqs; 159 struct irq_action *act; 160 161 /* Evaluate only irqs that are both enabled AND pending */ 162 irqs = rdctl (CTL_IENABLE) & rdctl (CTL_IPENDING); 163 act = vecs; 164 165 /* Assume (as does the Nios2 HAL) that bit 0 is highest 166 * priority. NOTE: There is ALWAYS a handler assigned 167 * (the default if no other). 168 */ 169 while (irqs) { 170 if (irqs & 1) { 171 act->handler (act->arg); 172 act->count++; 173 } 174 irqs >>=1; 175 act++; 176 } 177 } 178 179 static void def_hdlr (void *arg) 180 { 181 unsigned irqs = rdctl (CTL_IENABLE); 182 183 /* Disable the individual interrupt -- with gratuitous 184 * warning. 185 */ 186 irqs &= ~(1 << (int)arg); 187 wrctl (CTL_IENABLE, irqs); 188 printf ("WARNING: Disabling unhandled interrupt: %d\n", 189 (int)arg); 190 } 191 192 /*************************************************************************/ 193 void irq_install_handler (int irq, interrupt_handler_t *hdlr, void *arg) 194 { 195 196 int flag; 197 struct irq_action *act; 198 unsigned ena = rdctl (CTL_IENABLE); 199 200 if ((irq < 0) || (irq > 31)) 201 return; 202 act = &vecs[irq]; 203 204 flag = disable_interrupts (); 205 if (hdlr) { 206 act->handler = hdlr; 207 act->arg = arg; 208 ena |= (1 << irq); /* enable */ 209 } else { 210 act->handler = def_hdlr; 211 act->arg = (void *)irq; 212 ena &= ~(1 << irq); /* disable */ 213 } 214 wrctl (CTL_IENABLE, ena); 215 if (flag) enable_interrupts (); 216 } 217 218 219 int interrupt_init (void) 220 { 221 int i; 222 223 /* Assign the default handler to all */ 224 for (i = 0; i < 32; i++) { 225 vecs[i].handler = def_hdlr; 226 vecs[i].arg = (void *)i; 227 vecs[i].count = 0; 228 } 229 230 #if defined(CONFIG_SYS_NIOS_TMRBASE) 231 tmr_init (); 232 #endif 233 234 enable_interrupts (); 235 return (0); 236 } 237 238 239 /*************************************************************************/ 240 #if defined(CONFIG_CMD_IRQ) 241 int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 242 { 243 int i; 244 struct irq_action *act = vecs; 245 246 printf ("\nInterrupt-Information:\n\n"); 247 printf ("Nr Routine Arg Count\n"); 248 printf ("-----------------------------\n"); 249 250 for (i=0; i<32; i++) { 251 if (act->handler != def_hdlr) { 252 printf ("%02d %08lx %08lx %d\n", 253 i, 254 (ulong)act->handler, 255 (ulong)act->arg, 256 act->count); 257 } 258 act++; 259 } 260 printf ("\n"); 261 262 return (0); 263 } 264 #endif 265