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