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