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