xref: /rk3399_rockchip-uboot/arch/nios2/cpu/interrupts.c (revision 37e4dafaae96ccc970a896f90186fadcf858aad0)
1*37e4dafaSPeter Tyser /*
2*37e4dafaSPeter Tyser  * (C) Copyright 2000-2002
3*37e4dafaSPeter Tyser  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4*37e4dafaSPeter Tyser  *
5*37e4dafaSPeter Tyser  * (C) Copyright 2004, Psyent Corporation <www.psyent.com>
6*37e4dafaSPeter Tyser  * Scott McNutt <smcnutt@psyent.com>
7*37e4dafaSPeter Tyser  *
8*37e4dafaSPeter Tyser  * See file CREDITS for list of people who contributed to this
9*37e4dafaSPeter Tyser  * project.
10*37e4dafaSPeter Tyser  *
11*37e4dafaSPeter Tyser  * This program is free software; you can redistribute it and/or
12*37e4dafaSPeter Tyser  * modify it under the terms of the GNU General Public License as
13*37e4dafaSPeter Tyser  * published by the Free Software Foundation; either version 2 of
14*37e4dafaSPeter Tyser  * the License, or (at your option) any later version.
15*37e4dafaSPeter Tyser  *
16*37e4dafaSPeter Tyser  * This program is distributed in the hope that it will be useful,
17*37e4dafaSPeter Tyser  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18*37e4dafaSPeter Tyser  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19*37e4dafaSPeter Tyser  * GNU General Public License for more details.
20*37e4dafaSPeter Tyser  *
21*37e4dafaSPeter Tyser  * You should have received a copy of the GNU General Public License
22*37e4dafaSPeter Tyser  * along with this program; if not, write to the Free Software
23*37e4dafaSPeter Tyser  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
24*37e4dafaSPeter Tyser  * MA 02111-1307 USA
25*37e4dafaSPeter Tyser  */
26*37e4dafaSPeter Tyser 
27*37e4dafaSPeter Tyser 
28*37e4dafaSPeter Tyser #include <nios2.h>
29*37e4dafaSPeter Tyser #include <nios2-io.h>
30*37e4dafaSPeter Tyser #include <asm/types.h>
31*37e4dafaSPeter Tyser #include <asm/io.h>
32*37e4dafaSPeter Tyser #include <asm/ptrace.h>
33*37e4dafaSPeter Tyser #include <common.h>
34*37e4dafaSPeter Tyser #include <command.h>
35*37e4dafaSPeter Tyser #include <watchdog.h>
36*37e4dafaSPeter Tyser #ifdef CONFIG_STATUS_LED
37*37e4dafaSPeter Tyser #include <status_led.h>
38*37e4dafaSPeter Tyser #endif
39*37e4dafaSPeter Tyser 
40*37e4dafaSPeter Tyser #if defined(CONFIG_SYS_NIOS_TMRBASE) && !defined(CONFIG_SYS_NIOS_TMRIRQ)
41*37e4dafaSPeter Tyser #error CONFIG_SYS_NIOS_TMRIRQ not defined (see documentation)
42*37e4dafaSPeter Tyser #endif
43*37e4dafaSPeter Tyser 
44*37e4dafaSPeter Tyser /****************************************************************************/
45*37e4dafaSPeter Tyser 
46*37e4dafaSPeter Tyser struct	irq_action {
47*37e4dafaSPeter Tyser 	interrupt_handler_t *handler;
48*37e4dafaSPeter Tyser 	void *arg;
49*37e4dafaSPeter Tyser 	int count;
50*37e4dafaSPeter Tyser };
51*37e4dafaSPeter Tyser 
52*37e4dafaSPeter Tyser static struct irq_action vecs[32];
53*37e4dafaSPeter Tyser 
54*37e4dafaSPeter Tyser /*************************************************************************/
55*37e4dafaSPeter Tyser volatile ulong timestamp = 0;
56*37e4dafaSPeter Tyser 
57*37e4dafaSPeter Tyser void reset_timer (void)
58*37e4dafaSPeter Tyser {
59*37e4dafaSPeter Tyser 	nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
60*37e4dafaSPeter Tyser 
61*37e4dafaSPeter Tyser 	/* From Embedded Peripherals Handbook:
62*37e4dafaSPeter Tyser 	 *
63*37e4dafaSPeter Tyser 	 * "When the hardware is configured with Writeable period
64*37e4dafaSPeter Tyser 	 * disabled, writing to one of the period_n registers causes
65*37e4dafaSPeter Tyser 	 * the counter to reset to the fixed Timeout Period specified
66*37e4dafaSPeter Tyser 	 * at system generation time."
67*37e4dafaSPeter Tyser 	 *
68*37e4dafaSPeter Tyser 	 * Here we force a reload to prevent early timeouts from
69*37e4dafaSPeter Tyser 	 * get_timer() when the interrupt period is greater than
70*37e4dafaSPeter Tyser 	 * than 1 msec.
71*37e4dafaSPeter Tyser 	 *
72*37e4dafaSPeter Tyser 	 * Simply write to periodl with its own value to force an
73*37e4dafaSPeter Tyser 	 * internal counter reload, THEN reset the timestamp.
74*37e4dafaSPeter Tyser 	 */
75*37e4dafaSPeter Tyser 	writel (readl (&tmr->periodl), &tmr->periodl);
76*37e4dafaSPeter Tyser 	timestamp = 0;
77*37e4dafaSPeter Tyser 
78*37e4dafaSPeter Tyser 	/* From Embedded Peripherals Handbook:
79*37e4dafaSPeter Tyser 	 *
80*37e4dafaSPeter Tyser 	 * "Writing to one of the period_n registers stops the internal
81*37e4dafaSPeter Tyser 	 * counter, except when the hardware is configured with Start/Stop
82*37e4dafaSPeter Tyser 	 * control bits off. If Start/Stop control bits is off, writing
83*37e4dafaSPeter Tyser 	 * either register does not stop the counter."
84*37e4dafaSPeter Tyser 	 *
85*37e4dafaSPeter Tyser 	 * In order to accomodate either configuration, the control
86*37e4dafaSPeter Tyser 	 * register is re-written. If the counter is stopped, it will
87*37e4dafaSPeter Tyser 	 * be restarted. If it is running, the write is essentially
88*37e4dafaSPeter Tyser 	 * a nop.
89*37e4dafaSPeter Tyser 	 */
90*37e4dafaSPeter Tyser 	writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START,
91*37e4dafaSPeter Tyser 			&tmr->control);
92*37e4dafaSPeter Tyser 
93*37e4dafaSPeter Tyser }
94*37e4dafaSPeter Tyser 
95*37e4dafaSPeter Tyser ulong get_timer (ulong base)
96*37e4dafaSPeter Tyser {
97*37e4dafaSPeter Tyser 	WATCHDOG_RESET ();
98*37e4dafaSPeter Tyser 	return (timestamp - base);
99*37e4dafaSPeter Tyser }
100*37e4dafaSPeter Tyser 
101*37e4dafaSPeter Tyser void set_timer (ulong t)
102*37e4dafaSPeter Tyser {
103*37e4dafaSPeter Tyser 	timestamp = t;
104*37e4dafaSPeter Tyser }
105*37e4dafaSPeter Tyser 
106*37e4dafaSPeter Tyser 
107*37e4dafaSPeter Tyser /* The board must handle this interrupt if a timer is not
108*37e4dafaSPeter Tyser  * provided.
109*37e4dafaSPeter Tyser  */
110*37e4dafaSPeter Tyser #if defined(CONFIG_SYS_NIOS_TMRBASE)
111*37e4dafaSPeter Tyser void tmr_isr (void *arg)
112*37e4dafaSPeter Tyser {
113*37e4dafaSPeter Tyser 	nios_timer_t *tmr = (nios_timer_t *)arg;
114*37e4dafaSPeter Tyser 	/* Interrupt is cleared by writing anything to the
115*37e4dafaSPeter Tyser 	 * status register.
116*37e4dafaSPeter Tyser 	 */
117*37e4dafaSPeter Tyser 	writel (0, &tmr->status);
118*37e4dafaSPeter Tyser 	timestamp += CONFIG_SYS_NIOS_TMRMS;
119*37e4dafaSPeter Tyser #ifdef CONFIG_STATUS_LED
120*37e4dafaSPeter Tyser 	status_led_tick(timestamp);
121*37e4dafaSPeter Tyser #endif
122*37e4dafaSPeter Tyser }
123*37e4dafaSPeter Tyser 
124*37e4dafaSPeter Tyser static void tmr_init (void)
125*37e4dafaSPeter Tyser {
126*37e4dafaSPeter Tyser 	nios_timer_t *tmr =(nios_timer_t *)CONFIG_SYS_NIOS_TMRBASE;
127*37e4dafaSPeter Tyser 
128*37e4dafaSPeter Tyser 	writel (0, &tmr->status);
129*37e4dafaSPeter Tyser 	writel (0, &tmr->control);
130*37e4dafaSPeter Tyser 	writel (NIOS_TIMER_STOP, &tmr->control);
131*37e4dafaSPeter Tyser 
132*37e4dafaSPeter Tyser #if defined(CONFIG_SYS_NIOS_TMRCNT)
133*37e4dafaSPeter Tyser 	writel (CONFIG_SYS_NIOS_TMRCNT & 0xffff, &tmr->periodl);
134*37e4dafaSPeter Tyser 	writel ((CONFIG_SYS_NIOS_TMRCNT >> 16) & 0xffff, &tmr->periodh);
135*37e4dafaSPeter Tyser #endif
136*37e4dafaSPeter Tyser 	writel (NIOS_TIMER_ITO | NIOS_TIMER_CONT | NIOS_TIMER_START,
137*37e4dafaSPeter Tyser 			&tmr->control);
138*37e4dafaSPeter Tyser 	irq_install_handler (CONFIG_SYS_NIOS_TMRIRQ, tmr_isr, (void *)tmr);
139*37e4dafaSPeter Tyser }
140*37e4dafaSPeter Tyser 
141*37e4dafaSPeter Tyser #endif /* CONFIG_SYS_NIOS_TMRBASE */
142*37e4dafaSPeter Tyser 
143*37e4dafaSPeter Tyser /*************************************************************************/
144*37e4dafaSPeter Tyser int disable_interrupts (void)
145*37e4dafaSPeter Tyser {
146*37e4dafaSPeter Tyser 	int val = rdctl (CTL_STATUS);
147*37e4dafaSPeter Tyser 	wrctl (CTL_STATUS, val & ~STATUS_IE);
148*37e4dafaSPeter Tyser 	return (val & STATUS_IE);
149*37e4dafaSPeter Tyser }
150*37e4dafaSPeter Tyser 
151*37e4dafaSPeter Tyser void enable_interrupts( void )
152*37e4dafaSPeter Tyser {
153*37e4dafaSPeter Tyser 	int val = rdctl (CTL_STATUS);
154*37e4dafaSPeter Tyser 	wrctl (CTL_STATUS, val | STATUS_IE);
155*37e4dafaSPeter Tyser }
156*37e4dafaSPeter Tyser 
157*37e4dafaSPeter Tyser void external_interrupt (struct pt_regs *regs)
158*37e4dafaSPeter Tyser {
159*37e4dafaSPeter Tyser 	unsigned irqs;
160*37e4dafaSPeter Tyser 	struct irq_action *act;
161*37e4dafaSPeter Tyser 
162*37e4dafaSPeter Tyser 	/* Evaluate only irqs that are both enabled AND pending */
163*37e4dafaSPeter Tyser 	irqs = rdctl (CTL_IENABLE) & rdctl (CTL_IPENDING);
164*37e4dafaSPeter Tyser 	act = vecs;
165*37e4dafaSPeter Tyser 
166*37e4dafaSPeter Tyser 	/* Assume (as does the Nios2 HAL) that bit 0 is highest
167*37e4dafaSPeter Tyser 	 * priority. NOTE: There is ALWAYS a handler assigned
168*37e4dafaSPeter Tyser 	 * (the default if no other).
169*37e4dafaSPeter Tyser 	 */
170*37e4dafaSPeter Tyser 	while (irqs) {
171*37e4dafaSPeter Tyser 		if (irqs & 1) {
172*37e4dafaSPeter Tyser 			act->handler (act->arg);
173*37e4dafaSPeter Tyser 			act->count++;
174*37e4dafaSPeter Tyser 		}
175*37e4dafaSPeter Tyser 		irqs >>=1;
176*37e4dafaSPeter Tyser 		act++;
177*37e4dafaSPeter Tyser 	}
178*37e4dafaSPeter Tyser }
179*37e4dafaSPeter Tyser 
180*37e4dafaSPeter Tyser static void def_hdlr (void *arg)
181*37e4dafaSPeter Tyser {
182*37e4dafaSPeter Tyser 	unsigned irqs = rdctl (CTL_IENABLE);
183*37e4dafaSPeter Tyser 
184*37e4dafaSPeter Tyser 	/* Disable the individual interrupt -- with gratuitous
185*37e4dafaSPeter Tyser 	 * warning.
186*37e4dafaSPeter Tyser 	 */
187*37e4dafaSPeter Tyser 	irqs &= ~(1 << (int)arg);
188*37e4dafaSPeter Tyser 	wrctl (CTL_IENABLE, irqs);
189*37e4dafaSPeter Tyser 	printf ("WARNING: Disabling unhandled interrupt: %d\n",
190*37e4dafaSPeter Tyser 			(int)arg);
191*37e4dafaSPeter Tyser }
192*37e4dafaSPeter Tyser 
193*37e4dafaSPeter Tyser /*************************************************************************/
194*37e4dafaSPeter Tyser void irq_install_handler (int irq, interrupt_handler_t *hdlr, void *arg)
195*37e4dafaSPeter Tyser {
196*37e4dafaSPeter Tyser 
197*37e4dafaSPeter Tyser 	int flag;
198*37e4dafaSPeter Tyser 	struct irq_action *act;
199*37e4dafaSPeter Tyser 	unsigned ena = rdctl (CTL_IENABLE);
200*37e4dafaSPeter Tyser 
201*37e4dafaSPeter Tyser 	if ((irq < 0) || (irq > 31))
202*37e4dafaSPeter Tyser 		return;
203*37e4dafaSPeter Tyser 	act = &vecs[irq];
204*37e4dafaSPeter Tyser 
205*37e4dafaSPeter Tyser 	flag = disable_interrupts ();
206*37e4dafaSPeter Tyser 	if (hdlr) {
207*37e4dafaSPeter Tyser 		act->handler = hdlr;
208*37e4dafaSPeter Tyser 		act->arg = arg;
209*37e4dafaSPeter Tyser 		ena |= (1 << irq);		/* enable */
210*37e4dafaSPeter Tyser 	} else {
211*37e4dafaSPeter Tyser 		act->handler = def_hdlr;
212*37e4dafaSPeter Tyser 		act->arg = (void *)irq;
213*37e4dafaSPeter Tyser 		ena &= ~(1 << irq);		/* disable */
214*37e4dafaSPeter Tyser 	}
215*37e4dafaSPeter Tyser 	wrctl (CTL_IENABLE, ena);
216*37e4dafaSPeter Tyser 	if (flag) enable_interrupts ();
217*37e4dafaSPeter Tyser }
218*37e4dafaSPeter Tyser 
219*37e4dafaSPeter Tyser 
220*37e4dafaSPeter Tyser int interrupt_init (void)
221*37e4dafaSPeter Tyser {
222*37e4dafaSPeter Tyser 	int i;
223*37e4dafaSPeter Tyser 
224*37e4dafaSPeter Tyser 	/* Assign the default handler to all */
225*37e4dafaSPeter Tyser 	for (i = 0; i < 32; i++) {
226*37e4dafaSPeter Tyser 		vecs[i].handler = def_hdlr;
227*37e4dafaSPeter Tyser 		vecs[i].arg = (void *)i;
228*37e4dafaSPeter Tyser 		vecs[i].count = 0;
229*37e4dafaSPeter Tyser 	}
230*37e4dafaSPeter Tyser 
231*37e4dafaSPeter Tyser #if defined(CONFIG_SYS_NIOS_TMRBASE)
232*37e4dafaSPeter Tyser 	tmr_init ();
233*37e4dafaSPeter Tyser #endif
234*37e4dafaSPeter Tyser 
235*37e4dafaSPeter Tyser 	enable_interrupts ();
236*37e4dafaSPeter Tyser 	return (0);
237*37e4dafaSPeter Tyser }
238*37e4dafaSPeter Tyser 
239*37e4dafaSPeter Tyser 
240*37e4dafaSPeter Tyser /*************************************************************************/
241*37e4dafaSPeter Tyser #if defined(CONFIG_CMD_IRQ)
242*37e4dafaSPeter Tyser int do_irqinfo (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
243*37e4dafaSPeter Tyser {
244*37e4dafaSPeter Tyser 	int i;
245*37e4dafaSPeter Tyser 	struct irq_action *act = vecs;
246*37e4dafaSPeter Tyser 
247*37e4dafaSPeter Tyser 	printf ("\nInterrupt-Information:\n\n");
248*37e4dafaSPeter Tyser 	printf ("Nr  Routine   Arg       Count\n");
249*37e4dafaSPeter Tyser 	printf ("-----------------------------\n");
250*37e4dafaSPeter Tyser 
251*37e4dafaSPeter Tyser 	for (i=0; i<32; i++) {
252*37e4dafaSPeter Tyser 		if (act->handler != def_hdlr) {
253*37e4dafaSPeter Tyser 			printf ("%02d  %08lx  %08lx  %d\n",
254*37e4dafaSPeter Tyser 				i,
255*37e4dafaSPeter Tyser 				(ulong)act->handler,
256*37e4dafaSPeter Tyser 				(ulong)act->arg,
257*37e4dafaSPeter Tyser 				act->count);
258*37e4dafaSPeter Tyser 		}
259*37e4dafaSPeter Tyser 		act++;
260*37e4dafaSPeter Tyser 	}
261*37e4dafaSPeter Tyser 	printf ("\n");
262*37e4dafaSPeter Tyser 
263*37e4dafaSPeter Tyser 	return (0);
264*37e4dafaSPeter Tyser }
265*37e4dafaSPeter Tyser #endif
266