xref: /netbsd-src/sys/arch/newsmips/newsmips/news4000.c (revision cecde1b5250be188abd1ea1de5507e00d7ddefbe)
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