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