news5000.c revision 1.6 1 /* $NetBSD: news5000.c,v 1.6 2000/10/12 03:10:37 onoe 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) __P((struct timeval *tvp));
41
42 static void level1_intr __P((void));
43 static void level0_intr __P((void));
44
45 static u_int freerun_off;
46
47 /*
48 * Handle news5000 interrupts.
49 */
50 void
51 news5000_intr(status, cause, pc, ipending)
52 u_int status; /* status register at time of the exception */
53 u_int cause; /* cause register at time of exception */
54 u_int pc; /* program counter where to continue */
55 u_int ipending;
56 {
57 if (ipending & MIPS_INT_MASK_2) {
58 #ifdef DEBUG
59 static int l2cnt = 0;
60 #endif
61 u_int int2stat;
62 struct clockframe cf;
63
64 int2stat = *(volatile u_int *)NEWS5000_INTST2;
65
66 #ifdef DEBUG
67 l2cnt++;
68 if (l2cnt == 50) {
69 *(volatile u_int *)NEWS5000_LED_SEC = 1;
70 }
71 if (l2cnt == 100) {
72 *(volatile u_int *)NEWS5000_LED_SEC = 0;
73 l2cnt = 0;
74 }
75 #endif
76
77 if (int2stat & NEWS5000_INT2_TIMER0) {
78 *(volatile u_int *)NEWS5000_TIMER0 = 1;
79 freerun_off = *(volatile u_int *)NEWS5000_FREERUN;
80
81 cf.pc = pc;
82 cf.sr = status;
83
84 hardclock(&cf);
85 intrcnt[HARDCLOCK_INTR]++;
86 }
87
88 apbus_wbflush();
89 cause &= ~MIPS_INT_MASK_2;
90 }
91 /* If clock interrupts were enabled, re-enable them ASAP. */
92 _splset(MIPS_SR_INT_IE | (status & MIPS_INT_MASK_2));
93
94 if (ipending & MIPS_INT_MASK_5) {
95 u_int int5stat = *(volatile u_int *)NEWS5000_INTST5;
96 printf("level5 interrupt (%08x)\n", int5stat);
97
98 apbus_wbflush();
99 cause &= ~MIPS_INT_MASK_5;
100 }
101
102 if (ipending & MIPS_INT_MASK_4) {
103 u_int int4stat = *(volatile u_int *)NEWS5000_INTST4;
104 printf("level4 interrupt (%08x)\n", int4stat);
105 if (int4stat & NEWS5000_INT4_APBUS) {
106 u_int stat = *(volatile u_int *)NEWS5000_APBUS_INTST;
107 printf("APbus error 0x%04x\n", stat & 0xffff);
108 if (stat & NEWS5000_APBUS_INT_DMAADDR) {
109 printf("DMA Address Error: slot=%x, addr=0x%08x\n",
110 *(volatile u_int *)NEWS5000_APBUS_DER_S,
111 *(volatile u_int *)NEWS5000_APBUS_DER_A);
112 }
113 if (stat & NEWS5000_APBUS_INT_RDTIMEO)
114 printf("IO Read Timeout: addr=0x%08x\n",
115 *(volatile u_int *)NEWS5000_APBUS_BER_A);
116 if (stat & NEWS5000_APBUS_INT_WRTIMEO)
117 printf("IO Write Timeout: addr=0x%08x\n",
118 *(volatile u_int *)NEWS5000_APBUS_BER_A);
119 *(volatile u_int *)0xb4c00014 = stat;
120 }
121
122 apbus_wbflush();
123 cause &= ~MIPS_INT_MASK_4;
124 }
125
126 if (ipending & MIPS_INT_MASK_3) {
127 u_int int3stat = *(volatile u_int *)NEWS5000_INTST3;
128 printf("level3 interrupt (%08x)\n", int3stat);
129
130 apbus_wbflush();
131 cause &= ~MIPS_INT_MASK_3;
132 }
133
134 if (ipending & MIPS_INT_MASK_1) {
135 level1_intr();
136 apbus_wbflush();
137 cause &= ~MIPS_INT_MASK_1;
138 }
139
140 if (ipending & MIPS_INT_MASK_0) {
141 level0_intr();
142 apbus_wbflush();
143 cause &= ~MIPS_INT_MASK_0;
144 }
145
146 _splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
147 }
148
149
150 void
151 level1_intr()
152 {
153 u_int int1stat;
154
155 int1stat = *(volatile u_int *)NEWS5000_INTST1;
156
157 if (int1stat) {
158 if (apbus_intr_call(1, int1stat) == 0)
159 printf("level1_intr: no handler (mask 0x%04x)\n",
160 int1stat);
161 } else
162 printf("level1 stray interrupt?\n");
163 }
164
165 void
166 level0_intr()
167 {
168 u_int int0stat;
169
170 int0stat = *(volatile u_int *)NEWS5000_INTST0;
171
172 if (int0stat) {
173 if (apbus_intr_call(0, int0stat) == 0)
174 printf("level0_intr: no handler (mask 0x%04x)\n",
175 int0stat);
176 } else
177 printf("level0 stray interrupt?\n");
178 }
179
180 void
181 enable_intr_5000()
182 {
183
184 /* INT0 and INT1 has been enabled at attach */
185 /* INT2 -- It's not a time to enable timer yet. */
186 /* INT3 -- not used for NWS-5000 */
187
188 *(volatile u_int *)NEWS5000_INTEN4 = NEWS5000_INT4_APBUS;
189 *(volatile u_int *)NEWS5000_APBUS_INTMSK = 0xffff;
190
191 /* INT5 -- currently ignored */
192 *(volatile u_int *)NEWS5000_INTEN5 = 0;
193 }
194
195 void
196 disable_intr_5000()
197 {
198 *(volatile u_int *)NEWS5000_INTEN0 = 0;
199 *(volatile u_int *)NEWS5000_INTEN1 = 0;
200 *(volatile u_int *)NEWS5000_INTEN2 = 0;
201 *(volatile u_int *)NEWS5000_INTEN3 = 0;
202 *(volatile u_int *)NEWS5000_INTEN4 = 0;
203 *(volatile u_int *)NEWS5000_INTEN5 = 0;
204 }
205
206 void
207 readmicrotime_5000(tvp)
208 struct timeval *tvp;
209 {
210 u_int freerun;
211
212 *tvp = time;
213 freerun = *(volatile u_int *)NEWS5000_FREERUN;
214 freerun -= freerun_off;
215 if (freerun > 1000000)
216 freerun = 1000000;
217 tvp->tv_usec += freerun;
218 if (tvp->tv_usec >= 1000000) {
219 tvp->tv_usec -= 1000000;
220 tvp->tv_sec++;
221 }
222 }
223
224 void
225 readidrom_5000(rom)
226 u_char *rom;
227 {
228 u_int32_t *p = (void *)NEWS5000_IDROM;
229 int i;
230
231 for (i = 0; i < sizeof (struct idrom); i++, p += 2)
232 *rom++ = ((*p & 0x0f) << 4) + (*(p + 1) & 0x0f);
233 }
234
235 extern struct idrom idrom;
236
237 void
238 news5000_init()
239 {
240 enable_intr = enable_intr_5000;
241 disable_intr = disable_intr_5000;
242
243 readidrom_5000((u_char *)&idrom);
244 readmicrotime = readmicrotime_5000;
245 hostid = idrom.id_serial;
246 }
247