news5000.c revision 1.10 1 /* $NetBSD: news5000.c,v 1.10 2003/05/10 10:20:00 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/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 news5000_level1_intr(void);
43 static void news5000_level0_intr(void);
44
45 static void news5000_enable_intr(void);
46 static void news5000_disable_intr(void);
47 static void news5000_readmicrotime(struct timeval *);
48 static void news5000_readidrom(u_char *);
49
50 static u_int freerun_off;
51
52 /*
53 * Handle news5000 interrupts.
54 */
55 void
56 news5000_intr(status, cause, pc, ipending)
57 u_int status; /* status register at time of the exception */
58 u_int cause; /* cause register at time of exception */
59 u_int pc; /* program counter where to continue */
60 u_int ipending;
61 {
62 if (ipending & MIPS_INT_MASK_2) {
63 #ifdef DEBUG
64 static int l2cnt = 0;
65 #endif
66 u_int int2stat;
67 struct clockframe cf;
68
69 int2stat = *(volatile u_int *)NEWS5000_INTST2;
70
71 #ifdef DEBUG
72 l2cnt++;
73 if (l2cnt == 50) {
74 *(volatile u_int *)NEWS5000_LED_SEC = 1;
75 }
76 if (l2cnt == 100) {
77 *(volatile u_int *)NEWS5000_LED_SEC = 0;
78 l2cnt = 0;
79 }
80 #endif
81
82 if (int2stat & NEWS5000_INT2_TIMER0) {
83 *(volatile u_int *)NEWS5000_TIMER0 = 1;
84 freerun_off = *(volatile u_int *)NEWS5000_FREERUN;
85
86 cf.pc = pc;
87 cf.sr = status;
88
89 hardclock(&cf);
90 intrcnt[HARDCLOCK_INTR]++;
91 }
92
93 apbus_wbflush();
94 cause &= ~MIPS_INT_MASK_2;
95 }
96 /* If clock interrupts were enabled, re-enable them ASAP. */
97 _splset(MIPS_SR_INT_IE | (status & MIPS_INT_MASK_2));
98
99 if (ipending & MIPS_INT_MASK_5) {
100 u_int int5stat = *(volatile u_int *)NEWS5000_INTST5;
101 printf("level5 interrupt (%08x)\n", int5stat);
102
103 apbus_wbflush();
104 cause &= ~MIPS_INT_MASK_5;
105 }
106
107 if (ipending & MIPS_INT_MASK_4) {
108 u_int int4stat = *(volatile u_int *)NEWS5000_INTST4;
109 printf("level4 interrupt (%08x)\n", int4stat);
110 if (int4stat & NEWS5000_INT4_APBUS) {
111 u_int stat = *(volatile u_int *)NEWS5000_APBUS_INTST;
112 printf("APbus error 0x%04x\n", stat & 0xffff);
113 if (stat & NEWS5000_APBUS_INT_DMAADDR) {
114 printf("DMA Address Error: "
115 "slot=%x, addr=0x%08x\n",
116 *(volatile u_int *)NEWS5000_APBUS_DER_S,
117 *(volatile u_int *)NEWS5000_APBUS_DER_A);
118 }
119 if (stat & NEWS5000_APBUS_INT_RDTIMEO)
120 printf("IO Read Timeout: addr=0x%08x\n",
121 *(volatile u_int *)NEWS5000_APBUS_BER_A);
122 if (stat & NEWS5000_APBUS_INT_WRTIMEO)
123 printf("IO Write Timeout: addr=0x%08x\n",
124 *(volatile u_int *)NEWS5000_APBUS_BER_A);
125 *(volatile u_int *)0xb4c00014 = stat;
126 }
127
128 apbus_wbflush();
129 cause &= ~MIPS_INT_MASK_4;
130 }
131
132 if (ipending & MIPS_INT_MASK_3) {
133 u_int int3stat = *(volatile u_int *)NEWS5000_INTST3;
134 printf("level3 interrupt (%08x)\n", int3stat);
135
136 apbus_wbflush();
137 cause &= ~MIPS_INT_MASK_3;
138 }
139
140 if (ipending & MIPS_INT_MASK_1) {
141 news5000_level1_intr();
142 apbus_wbflush();
143 cause &= ~MIPS_INT_MASK_1;
144 }
145
146 if (ipending & MIPS_INT_MASK_0) {
147 news5000_level0_intr();
148 apbus_wbflush();
149 cause &= ~MIPS_INT_MASK_0;
150 }
151
152 _splset((status & ~cause & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE);
153 }
154
155
156 static void
157 news5000_level1_intr(void)
158 {
159 u_int int1stat;
160
161 int1stat = *(volatile u_int *)NEWS5000_INTST1;
162
163 if (int1stat) {
164 if (apbus_intr_dispatch(1, int1stat) == 0)
165 printf("level1_intr: no handler (mask 0x%04x)\n",
166 int1stat);
167 } else
168 printf("level1 stray interrupt?\n");
169 }
170
171 static void
172 news5000_level0_intr(void)
173 {
174 u_int int0stat;
175
176 int0stat = *(volatile u_int *)NEWS5000_INTST0;
177
178 if (int0stat) {
179 if (apbus_intr_dispatch(0, int0stat) == 0)
180 printf("level0_intr: no handler (mask 0x%04x)\n",
181 int0stat);
182 } else
183 printf("level0 stray interrupt?\n");
184 }
185
186 static void
187 news5000_enable_intr(void)
188 {
189
190 /* INT0 and INT1 has been enabled at attach */
191 /* INT2 -- It's not a time to enable timer yet. */
192 /* INT3 -- not used for NWS-5000 */
193
194 *(volatile u_int *)NEWS5000_INTEN4 = NEWS5000_INT4_APBUS;
195 *(volatile u_int *)NEWS5000_APBUS_INTMSK = 0xffff;
196
197 /* INT5 -- currently ignored */
198 *(volatile u_int *)NEWS5000_INTEN5 = 0;
199 }
200
201 static void
202 news5000_disable_intr(void)
203 {
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 news5000_readmicrotime(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 news5000_readidrom(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
248 enable_intr = news5000_enable_intr;
249 disable_intr = news5000_disable_intr;
250
251 news5000_readidrom((u_char *)&idrom);
252 readmicrotime = news5000_readmicrotime;
253 hostid = idrom.id_serial;
254
255 /* XXX reset uPD72067 FDC to avoid spurious interrupts */
256 #define NEWS5000_FDC_FDOUT 0xbed20000
257 #define FDO_FRST 0x04
258 *(volatile u_int8_t *)NEWS5000_FDC_FDOUT = FDO_FRST;
259 }
260