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