news5000.c revision 1.7 1 /* $NetBSD: news5000.c,v 1.7 2000/12/03 01:42:30 matt Exp $ */
2
3 /*-
4 * Copyright (C) 1999 SHIMIZU Ryo. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32
33 #include <machine/adrsmap.h>
34 #include <machine/cpu.h>
35 #include <machine/intr.h>
36
37 #include <newsmips/apbus/apbusvar.h>
38 #include <newsmips/newsmips/machid.h>
39
40 extern void (*readmicrotime) (struct timeval *tvp);
41
42 static void level1_intr (void);
43 static void level0_intr (void);
44
45 static void enable_intr_5000 (void);
46 static void disable_intr_5000 (void);
47 static void readmicrotime_5000 (struct timeval *);
48 static void readidrom_5000 (u_char *);
49
50 void news5000_init (void);
51
52 static u_int freerun_off;
53
54 /*
55 * Handle news5000 interrupts.
56 */
57 void
58 news5000_intr(status, cause, pc, ipending)
59 u_int status; /* status register at time of the exception */
60 u_int cause; /* cause register at time of exception */
61 u_int pc; /* program counter where to continue */
62 u_int ipending;
63 {
64 if (ipending & MIPS_INT_MASK_2) {
65 #ifdef DEBUG
66 static int l2cnt = 0;
67 #endif
68 u_int int2stat;
69 struct clockframe cf;
70
71 int2stat = *(volatile u_int *)NEWS5000_INTST2;
72
73 #ifdef DEBUG
74 l2cnt++;
75 if (l2cnt == 50) {
76 *(volatile u_int *)NEWS5000_LED_SEC = 1;
77 }
78 if (l2cnt == 100) {
79 *(volatile u_int *)NEWS5000_LED_SEC = 0;
80 l2cnt = 0;
81 }
82 #endif
83
84 if (int2stat & NEWS5000_INT2_TIMER0) {
85 *(volatile u_int *)NEWS5000_TIMER0 = 1;
86 freerun_off = *(volatile u_int *)NEWS5000_FREERUN;
87
88 cf.pc = pc;
89 cf.sr = status;
90
91 hardclock(&cf);
92 intrcnt[HARDCLOCK_INTR]++;
93 }
94
95 apbus_wbflush();
96 cause &= ~MIPS_INT_MASK_2;
97 }
98 /* If clock interrupts were enabled, re-enable them ASAP. */
99 _splset(MIPS_SR_INT_IE | (status & MIPS_INT_MASK_2));
100
101 if (ipending & MIPS_INT_MASK_5) {
102 u_int int5stat = *(volatile u_int *)NEWS5000_INTST5;
103 printf("level5 interrupt (%08x)\n", int5stat);
104
105 apbus_wbflush();
106 cause &= ~MIPS_INT_MASK_5;
107 }
108
109 if (ipending & MIPS_INT_MASK_4) {
110 u_int int4stat = *(volatile u_int *)NEWS5000_INTST4;
111 printf("level4 interrupt (%08x)\n", int4stat);
112 if (int4stat & NEWS5000_INT4_APBUS) {
113 u_int stat = *(volatile u_int *)NEWS5000_APBUS_INTST;
114 printf("APbus error 0x%04x\n", stat & 0xffff);
115 if (stat & NEWS5000_APBUS_INT_DMAADDR) {
116 printf("DMA Address Error: slot=%x, addr=0x%08x\n",
117 *(volatile u_int *)NEWS5000_APBUS_DER_S,
118 *(volatile u_int *)NEWS5000_APBUS_DER_A);
119 }
120 if (stat & NEWS5000_APBUS_INT_RDTIMEO)
121 printf("IO Read Timeout: addr=0x%08x\n",
122 *(volatile u_int *)NEWS5000_APBUS_BER_A);
123 if (stat & NEWS5000_APBUS_INT_WRTIMEO)
124 printf("IO Write Timeout: addr=0x%08x\n",
125 *(volatile u_int *)NEWS5000_APBUS_BER_A);
126 *(volatile u_int *)0xb4c00014 = stat;
127 }
128
129 apbus_wbflush();
130 cause &= ~MIPS_INT_MASK_4;
131 }
132
133 if (ipending & MIPS_INT_MASK_3) {
134 u_int int3stat = *(volatile u_int *)NEWS5000_INTST3;
135 printf("level3 interrupt (%08x)\n", int3stat);
136
137 apbus_wbflush();
138 cause &= ~MIPS_INT_MASK_3;
139 }
140
141 if (ipending & MIPS_INT_MASK_1) {
142 level1_intr();
143 apbus_wbflush();
144 cause &= ~MIPS_INT_MASK_1;
145 }
146
147 if (ipending & MIPS_INT_MASK_0) {
148 level0_intr();
149 apbus_wbflush();
150 cause &= ~MIPS_INT_MASK_0;
151 }
152
153 _splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
154 }
155
156
157 static void
158 level1_intr(void)
159 {
160 u_int int1stat;
161
162 int1stat = *(volatile u_int *)NEWS5000_INTST1;
163
164 if (int1stat) {
165 if (apbus_intr_call(1, int1stat) == 0)
166 printf("level1_intr: no handler (mask 0x%04x)\n",
167 int1stat);
168 } else
169 printf("level1 stray interrupt?\n");
170 }
171
172 static void
173 level0_intr(void)
174 {
175 u_int int0stat;
176
177 int0stat = *(volatile u_int *)NEWS5000_INTST0;
178
179 if (int0stat) {
180 if (apbus_intr_call(0, int0stat) == 0)
181 printf("level0_intr: no handler (mask 0x%04x)\n",
182 int0stat);
183 } else
184 printf("level0 stray interrupt?\n");
185 }
186
187 static void
188 enable_intr_5000(void)
189 {
190
191 /* INT0 and INT1 has been enabled at attach */
192 /* INT2 -- It's not a time to enable timer yet. */
193 /* INT3 -- not used for NWS-5000 */
194
195 *(volatile u_int *)NEWS5000_INTEN4 = NEWS5000_INT4_APBUS;
196 *(volatile u_int *)NEWS5000_APBUS_INTMSK = 0xffff;
197
198 /* INT5 -- currently ignored */
199 *(volatile u_int *)NEWS5000_INTEN5 = 0;
200 }
201
202 static void
203 disable_intr_5000(void)
204 {
205 *(volatile u_int *)NEWS5000_INTEN0 = 0;
206 *(volatile u_int *)NEWS5000_INTEN1 = 0;
207 *(volatile u_int *)NEWS5000_INTEN2 = 0;
208 *(volatile u_int *)NEWS5000_INTEN3 = 0;
209 *(volatile u_int *)NEWS5000_INTEN4 = 0;
210 *(volatile u_int *)NEWS5000_INTEN5 = 0;
211 }
212
213 static void
214 readmicrotime_5000(tvp)
215 struct timeval *tvp;
216 {
217 u_int freerun;
218
219 *tvp = time;
220 freerun = *(volatile u_int *)NEWS5000_FREERUN;
221 freerun -= freerun_off;
222 if (freerun > 1000000)
223 freerun = 1000000;
224 tvp->tv_usec += freerun;
225 if (tvp->tv_usec >= 1000000) {
226 tvp->tv_usec -= 1000000;
227 tvp->tv_sec++;
228 }
229 }
230
231 static void
232 readidrom_5000(rom)
233 u_char *rom;
234 {
235 u_int32_t *p = (void *)NEWS5000_IDROM;
236 int i;
237
238 for (i = 0; i < sizeof (struct idrom); i++, p += 2)
239 *rom++ = ((*p & 0x0f) << 4) + (*(p + 1) & 0x0f);
240 }
241
242 extern struct idrom idrom;
243
244 void
245 news5000_init(void)
246 {
247 enable_intr = enable_intr_5000;
248 disable_intr = disable_intr_5000;
249
250 readidrom_5000((u_char *)&idrom);
251 readmicrotime = readmicrotime_5000;
252 hostid = idrom.id_serial;
253 }
254