rmixl_usbi.c revision 1.1.2.2 1 /* $NetBSD: rmixl_usbi.c,v 1.1.2.2 2010/01/10 02:48:47 matt Exp $ */
2
3 /*-
4 * Copyright (c) 1998, 1999, 2000, 2002, 2003 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Cliff Neighbors
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 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: rmixl_usbi.c,v 1.1.2.2 2010/01/10 02:48:47 matt Exp $");
34
35 #include "locators.h"
36
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/device.h>
40
41 #include <machine/bus.h>
42
43 #include <mips/rmi/rmixlreg.h>
44 #include <mips/rmi/rmixlvar.h>
45 #include <mips/rmi/rmixl_obiovar.h>
46 #include <mips/rmi/rmixl_usbivar.h>
47
48 #include <dev/usb/usb.h>
49 #include <dev/usb/usbdi.h>
50 #include <dev/usb/usbdivar.h>
51 #include <dev/usb/usb_mem.h>
52
53 /*
54 * USB I/O register byte order is
55 * LITTLE ENDIAN regardless of code model
56 */
57 #define RMIXL_USBI_GEN_VADDR(o) \
58 (volatile uint32_t *)MIPS_PHYS_TO_KSEG1( \
59 rmixl_configuration.rc_io_pbase + RMIXL_IO_DEV_USB_B + (o))
60 #define RMIXL_USBI_GEN_READ(o) le32toh(*RMIXL_USBI_GEN_VADDR(o))
61 #define RMIXL_USBI_GEN_WRITE(o,v) *RMIXL_USBI_GEN_VADDR(o) = htole32(v)
62
63 static const char *rmixl_usbi_intrnames[RMIXL_UB_INTERRUPT_MAX+1] = {
64 "int 0 (ohci0)",
65 "int 1 (ohci1)",
66 "int 2 (ehci)",
67 "int 3 (device)",
68 "int 4 (phy)",
69 "int 5 (force)"
70 };
71
72 typedef struct rmixl_usbi_dispatch {
73 int (*func)(void *);
74 void *arg;
75 struct evcnt count;
76 } rmixl_usbi_dispatch_t;
77
78 typedef struct rmixl_usbi_softc {
79 device_t sc_dev;
80 bus_space_tag_t sc_eb_bst;
81 bus_space_tag_t sc_el_bst;
82 bus_addr_t sc_addr;
83 bus_size_t sc_size;
84 bus_dma_tag_t sc_dmat;
85 rmixl_usbi_dispatch_t sc_dispatch[RMIXL_UB_INTERRUPT_MAX + 1];
86 } rmixl_usbi_softc_t;
87
88
89 static int rmixl_usbi_match(device_t, cfdata_t, void *);
90 static void rmixl_usbi_attach(device_t, device_t, void *);
91 static int rmixl_usbi_print(void *, const char *);
92 static int rmixl_usbi_search(device_t, cfdata_t, const int *, void *);
93 static int rmixl_usbi_intr(void *);
94
95 #ifdef RMIXL_USBI_DEBUG
96 int rmixl_usbi_rdump(void);
97 rmixl_usbi_softc_t *rmixl_usbi_sc;
98 #endif
99
100
101 CFATTACH_DECL_NEW(rmixl_usbi, sizeof (rmixl_usbi_softc_t),
102 rmixl_usbi_match, rmixl_usbi_attach, NULL, NULL);
103
104 int
105 rmixl_usbi_match(device_t parent, cfdata_t match, void *aux)
106 {
107 struct obio_attach_args *obio = aux;
108
109 if (obio->obio_addr == RMIXL_IO_DEV_USB_B)
110 return 1;
111
112 return 0;
113 }
114
115 void
116 rmixl_usbi_attach(device_t parent, device_t self, void *aux)
117 {
118 rmixl_usbi_softc_t *sc = device_private(self);
119 struct obio_attach_args *obio = aux;
120 void *ih;
121
122 #ifdef RMIXL_USBI_DEBUG
123 rmixl_usbi_sc = sc;
124 #endif
125 sc->sc_dev = self;
126 sc->sc_eb_bst = obio->obio_eb_bst;
127 sc->sc_el_bst = obio->obio_el_bst;
128 sc->sc_addr = obio->obio_addr;
129 sc->sc_size = obio->obio_size;
130 sc->sc_dmat = obio->obio_32bit_dmat;
131
132 for (int intr=0; intr <= RMIXL_UB_INTERRUPT_MAX; intr++) {
133 evcnt_attach_dynamic(&sc->sc_dispatch[intr].count,
134 EVCNT_TYPE_INTR, NULL, "rmixl_usbi",
135 rmixl_usbi_intrnames[intr]);
136 }
137
138 /* Disable all usb interface interrupts */
139 RMIXL_USBI_GEN_WRITE(RMIXL_USB_INTERRUPT_ENABLE, 0);
140
141 /* establish interrupt */
142 ih = rmixl_intr_establish(obio->obio_intr, IPL_USB,
143 RMIXL_INTR_LEVEL, RMIXL_INTR_HIGH, rmixl_usbi_intr, sc);
144 if (ih == NULL)
145 panic("%s: couldn't establish interrupt", device_xname(self));
146
147 aprint_normal("\n");
148
149 /* attach any children */
150 config_search_ia(rmixl_usbi_search, self, "rmixl_usbi", NULL);
151 }
152
153 static int
154 rmixl_usbi_print(void *aux, const char *pnp)
155 {
156 struct rmixl_usbi_attach_args *usbi = aux;
157
158 if (usbi->usbi_addr != RMIXL_USBICF_ADDR_DEFAULT) {
159 aprint_normal(" addr %#"PRIxBUSADDR, usbi->usbi_addr);
160 if (usbi->usbi_size != RMIXL_USBICF_SIZE_DEFAULT)
161 aprint_normal("-%#"PRIxBUSADDR,
162 usbi->usbi_addr + (usbi->usbi_size - 1));
163 }
164 if (usbi->usbi_intr != RMIXL_USBICF_INTR_DEFAULT)
165 aprint_normal(" intr %d", usbi->usbi_intr);
166
167 aprint_normal("\n");
168
169 return (UNCONF);
170 }
171
172 static int
173 rmixl_usbi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
174 {
175 struct rmixl_usbi_softc *sc = device_private(parent);
176 struct rmixl_usbi_attach_args usbi;
177
178 usbi.usbi_eb_bst = sc->sc_eb_bst;
179 usbi.usbi_el_bst = sc->sc_el_bst;
180 usbi.usbi_addr = cf->cf_loc[RMIXL_USBICF_ADDR];
181 usbi.usbi_size = cf->cf_loc[RMIXL_USBICF_SIZE];
182 usbi.usbi_intr = cf->cf_loc[RMIXL_USBICF_INTR];
183 usbi.usbi_dmat = sc->sc_dmat;
184
185 if (config_match(parent, cf, &usbi) > 0)
186 config_attach(parent, cf, &usbi, rmixl_usbi_print);
187
188 return 0;
189 }
190
191
192 void
193 rmixl_usbi_intr_disestablish(void *uh, void *ih)
194 {
195 rmixl_usbi_softc_t *sc = uh;
196 u_int intr;
197
198 for (intr=0; intr <= RMIXL_UB_INTERRUPT_MAX; intr++) {
199 if (ih == &sc->sc_dispatch[intr]) {
200 uint32_t r;
201
202 /* disable this interrupt in the usb interface */
203 r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_ENABLE);
204 r &= 1 << intr;
205 RMIXL_USBI_GEN_WRITE(RMIXL_USB_INTERRUPT_ENABLE, r);
206
207 /* free the dispatch slot */
208 sc->sc_dispatch[intr].func = NULL;
209 sc->sc_dispatch[intr].arg = NULL;
210
211 break;
212 }
213 }
214 }
215
216 void *
217 rmixl_usbi_intr_establish(void *uh, u_int intr, int (func)(void *), void *arg)
218 {
219 rmixl_usbi_softc_t *sc = uh;
220 uint32_t r;
221 void *ih = NULL;
222 int s;
223
224 s = splusb();
225
226 if (intr > RMIXL_UB_INTERRUPT_MAX) {
227 aprint_error_dev(sc->sc_dev, "invalid intr %d\n", intr);
228 goto out;
229 }
230
231 if (sc->sc_dispatch[intr].func != NULL) {
232 aprint_error_dev(sc->sc_dev, "intr %dq busy\n", intr);
233 goto out;
234 }
235
236 sc->sc_dispatch[intr].func = func;
237 sc->sc_dispatch[intr].arg = arg;
238 ih = &sc->sc_dispatch[intr];
239
240 /* enable this interrupt in the usb interface */
241 r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_ENABLE);
242 r |= 1 << intr;
243 RMIXL_USBI_GEN_WRITE(RMIXL_USB_INTERRUPT_ENABLE, r);
244
245 out:
246 splx(s);
247 return ih;
248 }
249
250 static int
251 rmixl_usbi_intr(void *arg)
252 {
253 rmixl_usbi_softc_t *sc = arg;
254 uint32_t r;
255 int intr;
256 int rv = 0;
257
258 r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_STATUS);
259 if (r != 0) {
260 for (intr=0; intr <= RMIXL_UB_INTERRUPT_MAX; intr++) {
261 uint32_t bit = 1 << intr;
262 if ((r & bit) != 0) {
263 int (*f)(void *) = sc->sc_dispatch[intr].func;
264 void *a = sc->sc_dispatch[intr].arg;
265 if (f != NULL) {
266 (void)(*f)(a);
267 sc->sc_dispatch[intr].count.ev_count++;
268 rv = 1;
269 }
270 }
271 }
272 }
273
274 return rv;
275 }
276
277 #ifdef RMIXL_USBI_DEBUG
278 int
279 rmixl_usbi_rdump(void)
280 {
281 rmixl_usbi_softc_t *sc = rmixl_usbi_sc;
282 uint32_t r;
283
284 if (sc == NULL)
285 return -1;
286
287 printf("\n%s:\n", __func__);
288 r = RMIXL_USBI_GEN_READ(RMIXL_USB_GEN_CTRL1);
289 printf(" USB_GEN_CTRL1 %#x\n", r);
290 r = RMIXL_USBI_GEN_READ(RMIXL_USB_GEN_CTRL2);
291 printf(" USB_GEN_CTRL2 %#x\n", r);
292 r = RMIXL_USBI_GEN_READ(RMIXL_USB_GEN_CTRL3);
293 printf(" USB_GEN_CTRL3 %#x\n", r);
294 r = RMIXL_USBI_GEN_READ(RMIXL_USB_IOBM_TIMER);
295 printf(" USB_IOBM_TIMER %#x\n", r);
296 r = RMIXL_USBI_GEN_READ(RMIXL_USB_VBUS_TIMER);
297 printf(" USB_VBUS_TIMER %#x\n", r);
298 r = RMIXL_USBI_GEN_READ(RMIXL_USB_BYTESWAP_EN);
299 printf(" USB_BYTESWAP_EN %#x\n", r);
300 r = RMIXL_USBI_GEN_READ(RMIXL_USB_COHERENT_MEM_BASE);
301 printf(" USB_COHERENT_MEM_BASE %#x\n", r);
302 r = RMIXL_USBI_GEN_READ(RMIXL_USB_COHERENT_MEM_LIMIT);
303 printf(" USB_COHERENT_MEM_LIMIT %#x\n", r);
304 r = RMIXL_USBI_GEN_READ(RMIXL_USB_L2ALLOC_MEM_BASE);
305 printf(" USB_L2ALLOC_MEM_BASE %#x\n", r);
306 r = RMIXL_USBI_GEN_READ(RMIXL_USB_L2ALLOC_MEM_LIMIT);
307 printf(" USB_L2ALLOC_MEM_LIMIT %#x\n", r);
308 r = RMIXL_USBI_GEN_READ(RMIXL_USB_READEX_MEM_BASE);
309 printf(" USB_READEX_MEM_BASE %#x\n", r);
310 r = RMIXL_USBI_GEN_READ(RMIXL_USB_READEX_MEM_LIMIT);
311 printf(" USB_READEX_MEM_LIMIT %#x\n", r);
312 r = RMIXL_USBI_GEN_READ(RMIXL_USB_PHY_STATUS);
313 printf(" USB_PHY_STATUS %#x\n", r);
314 r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_STATUS);
315 printf(" USB_INTERRUPT_STATUS %#x\n", r);
316 r = RMIXL_USBI_GEN_READ(RMIXL_USB_INTERRUPT_ENABLE);
317 printf(" USB_INTERRUPT_ENABLE %#x\n", r);
318
319 return 0;
320 }
321 #endif
322