xref: /rk3399_rockchip-uboot/arch/nios2/cpu/interrupts.c (revision fea7f3aa3e5644b702be15d9076fe7b4b73db668)
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