xref: /netbsd/sys/arch/playstation2/dev/sbus.c (revision bf9ec67e)
1 /*	$NetBSD: sbus.c,v 1.1 2001/10/16 15:38:34 uch 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/param.h>
44 #include <sys/systm.h>
45 
46 #include <machine/bootinfo.h>
47 #include <machine/autoconf.h>
48 
49 #include <playstation2/playstation2/interrupt.h>
50 
51 #include <playstation2/ee/eevar.h>
52 #include <playstation2/ee/intcvar.h>
53 #include <playstation2/dev/sbusvar.h>
54 #include <playstation2/dev/sbusreg.h>
55 
56 #ifdef DEBUG
57 #define STATIC
58 #else
59 #define STATIC static
60 #endif
61 
62 STATIC void sbus_type2_pcmcia_intr_clear(void);
63 STATIC void sbus_type2_pcmcia_intr_enable(void);
64 STATIC void sbus_type2_pcmcia_intr_disable(void);
65 STATIC void sbus_type2_pcmcia_intr_reinstall(void);
66 STATIC void sbus_type3_pcmcia_intr_clear(void);
67 STATIC void sbus_type3_pcmcia_intr_enable(void);
68 STATIC void sbus_type3_pcmcia_intr_disable(void);
69 STATIC void sbus_type3_pcmcia_intr_reinstall(void);
70 STATIC int sbus_spurious_intr(void *);
71 
72 STATIC void (*sbus_pcmcia_intr_clear)(void);
73 STATIC void (*sbus_pcmcia_intr_enable)(void);
74 STATIC void (*sbus_pcmcia_intr_disable)(void);
75 STATIC void (*sbus_pcmcia_intr_reinstall)(void);
76 
77 STATIC int (*sbus_pcmcia_intr)(void *) = sbus_spurious_intr;
78 STATIC void *sbus_pcmcia_context;
79 STATIC int (*sbus_usb_intr)(void *) = sbus_spurious_intr;
80 STATIC void *sbus_usb_context;
81 
82 STATIC void sbus_init(int);
83 STATIC int sbus_intr(void *);
84 
85 STATIC int sbus_match(struct device *, struct cfdata *, void *);
86 STATIC void sbus_attach(struct device *, struct device *, void *);
87 STATIC int sbus_search(struct device *, struct cfdata *, void *);
88 STATIC int sbus_print(void *, const char *);
89 
90 struct cfattach sbus_ca = {
91 	sizeof (struct device), sbus_match, sbus_attach
92 };
93 
94 extern struct cfdriver sbus_cd;
95 STATIC int __sbus_attached;
96 
97 int
98 sbus_match(struct device *parent, struct cfdata *cf, void *aux)
99 {
100 	struct mainbus_attach_args *ma = aux;
101 
102 	if (strcmp(ma->ma_name, sbus_cd.cd_name) != 0)
103 		return (0);
104 
105 	return (!__sbus_attached);
106 }
107 
108 void
109 sbus_attach(struct device *parent, struct device *self, void *aux)
110 {
111 	int type = BOOTINFO_REF(BOOTINFO_PCMCIA_TYPE);
112 
113 	printf(": controller type %d\n", type);
114 
115 	/* Initialize SBUS controller */
116 	sbus_init(type);
117 
118 	config_search(sbus_search, self, 0);
119 }
120 
121 int
122 sbus_search(struct device *parent, struct cfdata *cf, void *aux)
123 {
124 	struct sbus_attach_args sa;
125 
126 	if ((*cf->cf_attach->ca_match)(parent, cf, &sa))
127 		config_attach(parent, cf, &sa, sbus_print);
128 
129 	return (0);
130 }
131 
132 int
133 sbus_print(void *aux, const char *pnp)
134 {
135 
136 	return (pnp ? QUIET : UNCONF);
137 }
138 
139 void
140 sbus_init(int type)
141 {
142 	/* install model dependent hook */
143 #define SET_PCMCIA_INTR_OPS(x)	 					\
144 	sbus_pcmcia_intr_clear = sbus_type##x##_pcmcia_intr_clear;	\
145 	sbus_pcmcia_intr_enable = sbus_type##x##_pcmcia_intr_enable;	\
146 	sbus_pcmcia_intr_disable = sbus_type##x##_pcmcia_intr_disable;	\
147 	sbus_pcmcia_intr_reinstall = sbus_type##x##_pcmcia_intr_reinstall
148 
149 	switch (type) {
150 	default:
151 		panic("unknown pcmcia controller type = %d", type);
152 		break;
153 	case 0:
154 		/* FALLTHROUGH */
155 	case 1:
156 		/* FALLTHROUGH */
157 	case 2:
158 		SET_PCMCIA_INTR_OPS(2);
159 		break;
160 	case 3:
161 		SET_PCMCIA_INTR_OPS(3);
162 		break;
163 	}
164 #undef SET_PCMCIA_INTR_OPS
165 	/* disable interrupt */
166 	(*sbus_pcmcia_intr_disable)();
167 
168 	/* clear interrupt */
169 	(*sbus_pcmcia_intr_clear)();
170 	_reg_write_4(SBUS_SMFLG_REG, SMFLG_PCMCIA_INT);
171 	_reg_write_4(SBUS_SMFLG_REG, SMFLG_USB_INT);
172 
173 	/* connect to INTC */
174 	intc_intr_establish(I_CH1_SBUS, IPL_BIO, sbus_intr, 0);
175 }
176 
177 void *
178 sbus_intr_establish(enum sbus_irq irq, int (*ih_func)(void *), void *ih_arg)
179 {
180 	switch (irq) {
181 	default:
182 		panic("unknown IRQ\n");
183 		break;
184 	case SBUS_IRQ_PCMCIA:
185 		sbus_pcmcia_intr = ih_func;
186 		sbus_pcmcia_context = ih_arg;
187 		(*sbus_pcmcia_intr_enable)();
188 		break;
189 	case SBUS_IRQ_USB:
190 		sbus_usb_intr = ih_func;
191 		sbus_usb_context = ih_arg;
192 		break;
193 	}
194 
195 	return (void *)irq;
196 }
197 
198 void
199 sbus_intr_disestablish(void *handle)
200 {
201 	int irq = (int)handle;
202 
203 	switch (irq) {
204 	default:
205 		panic("unknown IRQ\n");
206 		break;
207 	case SBUS_IRQ_PCMCIA:
208 		sbus_pcmcia_intr = sbus_spurious_intr;
209 		(*sbus_pcmcia_intr_disable)();
210 		break;
211 	case SBUS_IRQ_USB:
212 		sbus_usb_intr = sbus_spurious_intr;
213 		break;
214 	}
215 }
216 
217 int
218 sbus_intr(void *arg)
219 {
220 	u_int32_t stat;
221 
222 	_playstation2_evcnt.sbus.ev_count++;
223 	stat = _reg_read_4(SBUS_SMFLG_REG);
224 
225 	if (stat & SMFLG_PCMCIA_INT) {
226 		(*sbus_pcmcia_intr_clear)();
227 		_reg_write_4(SBUS_SMFLG_REG, SMFLG_PCMCIA_INT);
228 		(*sbus_pcmcia_intr)(sbus_pcmcia_context);
229 	}
230 
231 	if (stat & SMFLG_USB_INT) {
232 		_reg_write_4(SBUS_SMFLG_REG, SMFLG_USB_INT);
233 		(*sbus_usb_intr)(sbus_usb_context);
234 	}
235 
236 	(*sbus_pcmcia_intr_reinstall)();
237 
238 	return (1);
239 }
240 
241 int
242 sbus_spurious_intr(void *arg)
243 {
244 
245 	printf("spurious interrupt.\n");
246 
247 	return (1);
248 }
249 
250 /* SCPH-18000 */
251 void
252 sbus_type2_pcmcia_intr_clear()
253 {
254 
255 	if (_reg_read_2(SBUS_PCMCIA_CSC1_REG16) & 0x080)
256 		_reg_write_2(SBUS_PCMCIA_CSC1_REG16, 0xffff);
257 }
258 
259 void
260 sbus_type2_pcmcia_intr_enable()
261 {
262 
263 	_reg_write_2(SBUS_PCMCIA_TIMR_REG16, 0);
264 }
265 
266 void
267 sbus_type2_pcmcia_intr_disable()
268 {
269 
270 	_reg_write_2(SBUS_PCMCIA_TIMR_REG16, 1);
271 }
272 
273 void
274 sbus_type2_pcmcia_intr_reinstall()
275 {
276 	u_int16_t r = _reg_read_2(SBUS_PCMCIA_TIMR_REG16);
277 
278 	_reg_write_2(SBUS_PCMCIA_TIMR_REG16, 1);
279 	_reg_write_2(SBUS_PCMCIA_TIMR_REG16, r);
280 }
281 
282 /* SCPH-30000/35000 */
283 void
284 sbus_type3_pcmcia_intr_clear()
285 {
286 	/* nothing */
287 }
288 
289 void
290 sbus_type3_pcmcia_intr_enable()
291 {
292 
293 	_reg_write_2(SBUS_PCMCIA3_TIMR_REG16, 0);
294 }
295 
296 void
297 sbus_type3_pcmcia_intr_disable()
298 {
299 
300 	_reg_write_2(SBUS_PCMCIA3_TIMR_REG16, 1);
301 }
302 
303 void
304 sbus_type3_pcmcia_intr_reinstall()
305 {
306 	u_int16_t r = _reg_read_2(SBUS_PCMCIA3_TIMR_REG16);
307 
308 	_reg_write_2(SBUS_PCMCIA3_TIMR_REG16, 1);
309 	_reg_write_2(SBUS_PCMCIA3_TIMR_REG16, r);
310 }
311