sbus.c revision 1.6 1 /* $NetBSD: sbus.c,v 1.6 2003/07/15 02:54:36 lukem Exp $ */
2
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by UCHIYAMA Yasushi.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * PlayStation 2 internal PCMCIA/USB interface unit.
41 */
42
43 #include <sys/cdefs.h>
44 __KERNEL_RCSID(0, "$NetBSD: sbus.c,v 1.6 2003/07/15 02:54:36 lukem Exp $");
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48
49 #include <machine/bootinfo.h>
50 #include <machine/autoconf.h>
51
52 #include <playstation2/playstation2/interrupt.h>
53
54 #include <playstation2/ee/eevar.h>
55 #include <playstation2/ee/intcvar.h>
56 #include <playstation2/dev/sbusvar.h>
57 #include <playstation2/dev/sbusreg.h>
58
59 #ifdef DEBUG
60 #define STATIC
61 #else
62 #define STATIC static
63 #endif
64
65 STATIC void sbus_type2_pcmcia_intr_clear(void);
66 STATIC void sbus_type2_pcmcia_intr_enable(void);
67 STATIC void sbus_type2_pcmcia_intr_disable(void);
68 STATIC void sbus_type2_pcmcia_intr_reinstall(void);
69 STATIC void sbus_type3_pcmcia_intr_clear(void);
70 STATIC void sbus_type3_pcmcia_intr_enable(void);
71 STATIC void sbus_type3_pcmcia_intr_disable(void);
72 STATIC void sbus_type3_pcmcia_intr_reinstall(void);
73 STATIC int sbus_spurious_intr(void *);
74
75 STATIC void (*sbus_pcmcia_intr_clear)(void);
76 STATIC void (*sbus_pcmcia_intr_enable)(void);
77 STATIC void (*sbus_pcmcia_intr_disable)(void);
78 STATIC void (*sbus_pcmcia_intr_reinstall)(void);
79
80 STATIC int (*sbus_pcmcia_intr)(void *) = sbus_spurious_intr;
81 STATIC void *sbus_pcmcia_context;
82 STATIC int (*sbus_usb_intr)(void *) = sbus_spurious_intr;
83 STATIC void *sbus_usb_context;
84
85 STATIC void sbus_init(int);
86 STATIC int sbus_intr(void *);
87
88 STATIC int sbus_match(struct device *, struct cfdata *, void *);
89 STATIC void sbus_attach(struct device *, struct device *, void *);
90 STATIC int sbus_search(struct device *, struct cfdata *, void *);
91 STATIC int sbus_print(void *, const char *);
92
93 CFATTACH_DECL(sbus, sizeof (struct device),
94 sbus_match, sbus_attach, NULL, NULL);
95
96 extern struct cfdriver sbus_cd;
97 STATIC int __sbus_attached;
98
99 int
100 sbus_match(struct device *parent, struct cfdata *cf, void *aux)
101 {
102 struct mainbus_attach_args *ma = aux;
103
104 if (strcmp(ma->ma_name, sbus_cd.cd_name) != 0)
105 return (0);
106
107 return (!__sbus_attached);
108 }
109
110 void
111 sbus_attach(struct device *parent, struct device *self, void *aux)
112 {
113 int type = BOOTINFO_REF(BOOTINFO_PCMCIA_TYPE);
114
115 printf(": controller type %d\n", type);
116
117 /* Initialize SBUS controller */
118 sbus_init(type);
119
120 config_search(sbus_search, self, 0);
121 }
122
123 int
124 sbus_search(struct device *parent, struct cfdata *cf, void *aux)
125 {
126 struct sbus_attach_args sa;
127
128 if (config_match(parent, cf, &sa))
129 config_attach(parent, cf, &sa, sbus_print);
130
131 return (0);
132 }
133
134 int
135 sbus_print(void *aux, const char *pnp)
136 {
137
138 return (pnp ? QUIET : UNCONF);
139 }
140
141 void
142 sbus_init(int type)
143 {
144 /* install model dependent hook */
145 #define SET_PCMCIA_INTR_OPS(x) \
146 sbus_pcmcia_intr_clear = sbus_type##x##_pcmcia_intr_clear; \
147 sbus_pcmcia_intr_enable = sbus_type##x##_pcmcia_intr_enable; \
148 sbus_pcmcia_intr_disable = sbus_type##x##_pcmcia_intr_disable; \
149 sbus_pcmcia_intr_reinstall = sbus_type##x##_pcmcia_intr_reinstall
150
151 switch (type) {
152 default:
153 panic("unknown pcmcia controller type = %d", type);
154 break;
155 case 0:
156 /* FALLTHROUGH */
157 case 1:
158 /* FALLTHROUGH */
159 case 2:
160 SET_PCMCIA_INTR_OPS(2);
161 break;
162 case 3:
163 SET_PCMCIA_INTR_OPS(3);
164 break;
165 }
166 #undef SET_PCMCIA_INTR_OPS
167 /* disable interrupt */
168 (*sbus_pcmcia_intr_disable)();
169
170 /* clear interrupt */
171 (*sbus_pcmcia_intr_clear)();
172 _reg_write_4(SBUS_SMFLG_REG, SMFLG_PCMCIA_INT);
173 _reg_write_4(SBUS_SMFLG_REG, SMFLG_USB_INT);
174
175 /* connect to INTC */
176 intc_intr_establish(I_CH1_SBUS, IPL_BIO, sbus_intr, 0);
177 }
178
179 void *
180 sbus_intr_establish(enum sbus_irq irq, int (*ih_func)(void *), void *ih_arg)
181 {
182 switch (irq) {
183 default:
184 panic("unknown IRQ");
185 break;
186 case SBUS_IRQ_PCMCIA:
187 sbus_pcmcia_intr = ih_func;
188 sbus_pcmcia_context = ih_arg;
189 (*sbus_pcmcia_intr_enable)();
190 break;
191 case SBUS_IRQ_USB:
192 sbus_usb_intr = ih_func;
193 sbus_usb_context = ih_arg;
194 break;
195 }
196
197 return (void *)irq;
198 }
199
200 void
201 sbus_intr_disestablish(void *handle)
202 {
203 int irq = (int)handle;
204
205 switch (irq) {
206 default:
207 panic("unknown IRQ");
208 break;
209 case SBUS_IRQ_PCMCIA:
210 sbus_pcmcia_intr = sbus_spurious_intr;
211 (*sbus_pcmcia_intr_disable)();
212 break;
213 case SBUS_IRQ_USB:
214 sbus_usb_intr = sbus_spurious_intr;
215 break;
216 }
217 }
218
219 int
220 sbus_intr(void *arg)
221 {
222 u_int32_t stat;
223
224 _playstation2_evcnt.sbus.ev_count++;
225 stat = _reg_read_4(SBUS_SMFLG_REG);
226
227 if (stat & SMFLG_PCMCIA_INT) {
228 (*sbus_pcmcia_intr_clear)();
229 _reg_write_4(SBUS_SMFLG_REG, SMFLG_PCMCIA_INT);
230 (*sbus_pcmcia_intr)(sbus_pcmcia_context);
231 }
232
233 if (stat & SMFLG_USB_INT) {
234 _reg_write_4(SBUS_SMFLG_REG, SMFLG_USB_INT);
235 (*sbus_usb_intr)(sbus_usb_context);
236 }
237
238 (*sbus_pcmcia_intr_reinstall)();
239
240 return (1);
241 }
242
243 int
244 sbus_spurious_intr(void *arg)
245 {
246
247 printf("spurious interrupt.\n");
248
249 return (1);
250 }
251
252 /* SCPH-18000 */
253 void
254 sbus_type2_pcmcia_intr_clear()
255 {
256
257 if (_reg_read_2(SBUS_PCMCIA_CSC1_REG16) & 0x080)
258 _reg_write_2(SBUS_PCMCIA_CSC1_REG16, 0xffff);
259 }
260
261 void
262 sbus_type2_pcmcia_intr_enable()
263 {
264
265 _reg_write_2(SBUS_PCMCIA_TIMR_REG16, 0);
266 }
267
268 void
269 sbus_type2_pcmcia_intr_disable()
270 {
271
272 _reg_write_2(SBUS_PCMCIA_TIMR_REG16, 1);
273 }
274
275 void
276 sbus_type2_pcmcia_intr_reinstall()
277 {
278 u_int16_t r = _reg_read_2(SBUS_PCMCIA_TIMR_REG16);
279
280 _reg_write_2(SBUS_PCMCIA_TIMR_REG16, 1);
281 _reg_write_2(SBUS_PCMCIA_TIMR_REG16, r);
282 }
283
284 /* SCPH-30000/35000 */
285 void
286 sbus_type3_pcmcia_intr_clear()
287 {
288 /* nothing */
289 }
290
291 void
292 sbus_type3_pcmcia_intr_enable()
293 {
294
295 _reg_write_2(SBUS_PCMCIA3_TIMR_REG16, 0);
296 }
297
298 void
299 sbus_type3_pcmcia_intr_disable()
300 {
301
302 _reg_write_2(SBUS_PCMCIA3_TIMR_REG16, 1);
303 }
304
305 void
306 sbus_type3_pcmcia_intr_reinstall()
307 {
308 u_int16_t r = _reg_read_2(SBUS_PCMCIA3_TIMR_REG16);
309
310 _reg_write_2(SBUS_PCMCIA3_TIMR_REG16, 1);
311 _reg_write_2(SBUS_PCMCIA3_TIMR_REG16, r);
312 }
313