1 /* $NetBSD: news4000.c,v 1.2 2024/06/02 13:28:44 andvar Exp $ */
2
3 /*-
4 * Copyright (C) 2000 NONAKA Kimihiro. 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 #define __INTR_PRIVATE
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/timetc.h>
34 #include <sys/intr.h>
35
36 #include <machine/adrsmap.h>
37 #include <machine/cpu.h>
38
39 #include <mips/locore.h>
40
41 #include <newsmips/apbus/apbusvar.h>
42 #include <newsmips/newsmips/machid.h>
43
44 static void news4000_level0_intr(void);
45 static void news4000_level1_intr(void);
46
47 static void news4000_enable_intr(void);
48 static void news4000_disable_intr(void);
49 static void news4000_enable_timer(void);
50 static void news4000_readidrom(uint8_t *);
51
52 /*
53 * This is a mask of bits of to clear in the SR when we go to a
54 * given interrupt priority level.
55 */
56 static const struct ipl_sr_map news4000_ipl_sr_map = {
57 .sr_bits = {
58 [IPL_NONE] = 0,
59 [IPL_SOFTCLOCK] = MIPS_SOFT_INT_MASK_0,
60 [IPL_SOFTNET] = MIPS_SOFT_INT_MASK,
61 [IPL_VM] = MIPS_SOFT_INT_MASK
62 | MIPS_INT_MASK_0
63 | MIPS_INT_MASK_1,
64 [IPL_SCHED] = MIPS_SOFT_INT_MASK
65 | MIPS_INT_MASK_0
66 | MIPS_INT_MASK_1
67 | MIPS_INT_MASK_2,
68 [IPL_DDB] = MIPS_INT_MASK,
69 [IPL_HIGH] = MIPS_INT_MASK,
70 },
71 };
72
73 /*
74 * Handle news4000 interrupts.
75 */
76 void
news4000_intr(int ppl,vaddr_t pc,uint32_t status)77 news4000_intr(int ppl, vaddr_t pc, uint32_t status)
78 {
79 uint32_t ipending;
80 int ipl;
81
82 while (ppl < (ipl = splintr(&ipending))) {
83 if (ipending & MIPS_INT_MASK_2) {
84 uint32_t int2stat;
85
86 int2stat = *(volatile uint32_t *)NEWS4000_INTST2;
87
88 if (int2stat & NEWS4000_INT2_TIMER) {
89 struct clockframe cf = {
90 .pc = pc,
91 .sr = status,
92 .intr = (curcpu()->ci_idepth > 1),
93 };
94 *(volatile uint32_t *)NEWS4000_TIMER = 1;
95
96 hardclock(&cf);
97 intrcnt[HARDCLOCK_INTR]++;
98 }
99
100 apbus_wbflush();
101 }
102
103 if (ipending & MIPS_INT_MASK_5) {
104 uint32_t int5stat =
105 *(volatile uint32_t *)NEWS4000_INTST5;
106 printf("level5 interrupt: status = %04x\n", int5stat);
107 apbus_wbflush();
108 }
109
110 if (ipending & MIPS_INT_MASK_4) {
111 uint32_t int4stat =
112 *(volatile uint32_t *)NEWS4000_INTST4;
113 printf("level4 interrupt: status = %04x\n", int4stat);
114 apbus_wbflush();
115 }
116
117 if (ipending & MIPS_INT_MASK_3) {
118 printf("level3 interrupt\n");
119 apbus_wbflush();
120 }
121
122 if (ipending & MIPS_INT_MASK_1) {
123 news4000_level1_intr();
124 apbus_wbflush();
125 }
126
127 if (ipending & MIPS_INT_MASK_0) {
128 news4000_level0_intr();
129 apbus_wbflush();
130 }
131 }
132 }
133
134 static void
news4000_level1_intr(void)135 news4000_level1_intr(void)
136 {
137 uint32_t int1stat;
138
139 int1stat = *(volatile uint32_t *)NEWS4000_INTST1;
140
141 #if 0
142 *(volatile uint32_t *)NEWS4000_LED = 0xe; /* XXX */
143 #endif
144
145 printf("level1_intr stat = 0x%x\n", int1stat);
146
147 if (int1stat) {
148 if (apbus_intr_dispatch(1, int1stat) == 0)
149 printf("level1_intr: no handler (mask 0x%04x)\n",
150 int1stat);
151 } else
152 printf("level1 stray interrupt?\n");
153 }
154
155 static void
news4000_level0_intr(void)156 news4000_level0_intr(void)
157 {
158 uint32_t int0stat;
159
160 int0stat = *(volatile uint32_t *)NEWS4000_INTST0;
161
162 if (int0stat) {
163 if (apbus_intr_dispatch(0, int0stat) == 0)
164 printf("level0_intr: no handler (mask 0x%04x)\n",
165 int0stat);
166 } else
167 printf("level0 stray interrupt?\n");
168 }
169
170 static void
news4000_enable_intr(void)171 news4000_enable_intr(void)
172 {
173
174 *(volatile uint32_t *)NEWS4000_INTEN0 = 0xffffffff;
175 *(volatile uint32_t *)NEWS4000_INTEN1 = 0xffffffff;
176 *(volatile uint32_t *)NEWS4000_INTEN2 = 1;
177 *(volatile uint32_t *)NEWS4000_INTEN3 = 0;
178 *(volatile uint32_t *)NEWS4000_INTEN4 = 0; /* 3 */
179 *(volatile uint32_t *)NEWS4000_INTEN5 = 0; /* 3 */
180 }
181
182 static void
news4000_disable_intr(void)183 news4000_disable_intr(void)
184 {
185
186 *(volatile uint32_t *)NEWS4000_INTEN0 = 0;
187 *(volatile uint32_t *)NEWS4000_INTEN1 = 0;
188 *(volatile uint32_t *)NEWS4000_INTEN2 = 0;
189 *(volatile uint32_t *)NEWS4000_INTEN3 = 0;
190 *(volatile uint32_t *)NEWS4000_INTEN4 = 0;
191 *(volatile uint32_t *)NEWS4000_INTEN5 = 0;
192 }
193
194 static void
news4000_enable_timer(void)195 news4000_enable_timer(void)
196 {
197
198 #if 0
199 news4000_tc_init();
200 #endif
201
202 /* enable timer interrupt */
203 *(volatile uint32_t *)NEWS4000_TIMERCTL = 1;
204 }
205
206 extern struct idrom idrom;
207
208 static void
news4000_readidrom(uint8_t * rom)209 news4000_readidrom(uint8_t *rom)
210 {
211 volatile uint32_t *status_port = (uint32_t *)NEWS4000_IDROM_STATUS;
212 volatile uint32_t *data_port = (uint32_t *)NEWS4000_IDROM_DATA;
213 int offset;
214
215 while ((*status_port & 1) == 0)
216 continue;
217
218 for (offset = 0; offset < sizeof(struct idrom); offset++, rom++) {
219 *data_port = offset;
220
221 while ((*status_port & 1) == 0)
222 continue;
223
224 *rom = (uint8_t)(*data_port & 0xff);
225 }
226 }
227
228 void
news4000_init(void)229 news4000_init(void)
230 {
231
232 ipl_sr_map = news4000_ipl_sr_map;
233
234 enable_intr = news4000_enable_intr;
235 disable_intr = news4000_disable_intr;
236 enable_timer = news4000_enable_timer;
237
238 news_wbflush = (uint32_t *)NEWS4000_WBFLUSH;
239
240 news4000_readidrom((uint8_t *)&idrom);
241 hostid = idrom.id_serial;
242 }
243