octusb_octeon.c revision 228483
1210312Sjmallett#include <sys/cdefs.h>
2210312Sjmallett__FBSDID("$FreeBSD: head/sys/mips/cavium/usb/octusb_octeon.c 228483 2011-12-14 00:28:54Z hselasky $");
3210312Sjmallett
4210312Sjmallett/*-
5210312Sjmallett * Copyright (c) 2007-2008 Hans Petter Selasky. All rights reserved.
6210312Sjmallett *
7210312Sjmallett * Redistribution and use in source and binary forms, with or without
8210312Sjmallett * modification, are permitted provided that the following conditions
9210312Sjmallett * are met:
10210312Sjmallett * 1. Redistributions of source code must retain the above copyright
11210312Sjmallett *    notice, this list of conditions and the following disclaimer.
12210312Sjmallett * 2. Redistributions in binary form must reproduce the above copyright
13210312Sjmallett *    notice, this list of conditions and the following disclaimer in the
14210312Sjmallett *    documentation and/or other materials provided with the distribution.
15210312Sjmallett *
16210312Sjmallett * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17210312Sjmallett * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18210312Sjmallett * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19210312Sjmallett * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20210312Sjmallett * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21210312Sjmallett * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22210312Sjmallett * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23210312Sjmallett * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24210312Sjmallett * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25210312Sjmallett * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26210312Sjmallett * SUCH DAMAGE.
27210312Sjmallett */
28210312Sjmallett
29210312Sjmallett#include <sys/stdint.h>
30210312Sjmallett#include <sys/stddef.h>
31210312Sjmallett#include <sys/param.h>
32210312Sjmallett#include <sys/queue.h>
33210312Sjmallett#include <sys/types.h>
34210312Sjmallett#include <sys/systm.h>
35210312Sjmallett#include <sys/kernel.h>
36210312Sjmallett#include <sys/bus.h>
37210312Sjmallett#include <sys/module.h>
38210312Sjmallett#include <sys/lock.h>
39210312Sjmallett#include <sys/mutex.h>
40210312Sjmallett#include <sys/condvar.h>
41210312Sjmallett#include <sys/sysctl.h>
42210312Sjmallett#include <sys/sx.h>
43210312Sjmallett#include <sys/unistd.h>
44210312Sjmallett#include <sys/callout.h>
45210312Sjmallett#include <sys/malloc.h>
46210312Sjmallett#include <sys/priv.h>
47210312Sjmallett#include <sys/rman.h>
48210312Sjmallett
49210312Sjmallett#include <dev/usb/usb.h>
50210312Sjmallett#include <dev/usb/usbdi.h>
51210312Sjmallett
52210312Sjmallett#include <dev/usb/usb_core.h>
53210312Sjmallett#include <dev/usb/usb_busdma.h>
54210312Sjmallett#include <dev/usb/usb_process.h>
55210312Sjmallett#include <dev/usb/usb_util.h>
56210312Sjmallett
57210312Sjmallett#include <dev/usb/usb_controller.h>
58210312Sjmallett#include <dev/usb/usb_bus.h>
59210312Sjmallett
60210312Sjmallett#include <contrib/octeon-sdk/cvmx.h>
61210312Sjmallett#include <contrib/octeon-sdk/cvmx-interrupt.h>
62210312Sjmallett#include <contrib/octeon-sdk/cvmx-usb.h>
63210312Sjmallett
64210312Sjmallett#include <mips/cavium/usb/octusb.h>
65210312Sjmallett
66210312Sjmallett#define	MEM_RID	0
67210312Sjmallett
68210312Sjmallettstatic device_identify_t octusb_octeon_identify;
69210312Sjmallettstatic device_probe_t octusb_octeon_probe;
70210312Sjmallettstatic device_attach_t octusb_octeon_attach;
71210312Sjmallettstatic device_detach_t octusb_octeon_detach;
72210312Sjmallettstatic device_shutdown_t octusb_octeon_shutdown;
73210312Sjmallett
74210312Sjmallettstruct octusb_octeon_softc {
75210312Sjmallett	struct octusb_softc sc_dci;	/* must be first */
76210312Sjmallett};
77210312Sjmallett
78210312Sjmallettstatic void
79210312Sjmallettoctusb_octeon_identify(driver_t *drv, device_t parent)
80210312Sjmallett{
81210312Sjmallett	if (octeon_has_feature(OCTEON_FEATURE_USB))
82210312Sjmallett		BUS_ADD_CHILD(parent, 0, "octusb", 0);
83210312Sjmallett}
84210312Sjmallett
85210312Sjmallettstatic int
86210312Sjmallettoctusb_octeon_probe(device_t dev)
87210312Sjmallett{
88210312Sjmallett	device_set_desc(dev, "Cavium Octeon USB controller");
89210312Sjmallett	return (0);
90210312Sjmallett}
91210312Sjmallett
92210312Sjmallettstatic int
93210312Sjmallettoctusb_octeon_attach(device_t dev)
94210312Sjmallett{
95210312Sjmallett	struct octusb_octeon_softc *sc = device_get_softc(dev);
96210312Sjmallett	int err;
97210312Sjmallett	int rid;
98210312Sjmallett
99210312Sjmallett	/* setup controller interface softc */
100210312Sjmallett
101210312Sjmallett	/* initialise some bus fields */
102210312Sjmallett	sc->sc_dci.sc_bus.parent = dev;
103210312Sjmallett	sc->sc_dci.sc_bus.devices = sc->sc_dci.sc_devices;
104210312Sjmallett	sc->sc_dci.sc_bus.devices_max = OCTUSB_MAX_DEVICES;
105210312Sjmallett
106210312Sjmallett	/* get all DMA memory */
107210312Sjmallett	if (usb_bus_mem_alloc_all(&sc->sc_dci.sc_bus,
108210312Sjmallett	    USB_GET_DMA_TAG(dev), NULL)) {
109210312Sjmallett		return (ENOMEM);
110210312Sjmallett	}
111210312Sjmallett	rid = 0;
112210312Sjmallett	sc->sc_dci.sc_irq_res =
113210312Sjmallett	    bus_alloc_resource(dev, SYS_RES_IRQ, &rid,
114210312Sjmallett			       CVMX_IRQ_USB, CVMX_IRQ_USB, 1, RF_ACTIVE);
115210312Sjmallett	if (!(sc->sc_dci.sc_irq_res)) {
116210312Sjmallett		goto error;
117210312Sjmallett	}
118210312Sjmallett
119210312Sjmallett	sc->sc_dci.sc_bus.bdev = device_add_child(dev, "usbus", -1);
120210312Sjmallett	if (!(sc->sc_dci.sc_bus.bdev)) {
121210312Sjmallett		goto error;
122210312Sjmallett	}
123210312Sjmallett	device_set_ivars(sc->sc_dci.sc_bus.bdev, &sc->sc_dci.sc_bus);
124210312Sjmallett
125210312Sjmallett#if (__FreeBSD_version >= 700031)
126210312Sjmallett	err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
127210312Sjmallett	    NULL, (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
128210312Sjmallett#else
129210312Sjmallett	err = bus_setup_intr(dev, sc->sc_dci.sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE,
130210312Sjmallett	    (driver_intr_t *)octusb_interrupt, sc, &sc->sc_dci.sc_intr_hdl);
131210312Sjmallett#endif
132210312Sjmallett	if (err) {
133210312Sjmallett		sc->sc_dci.sc_intr_hdl = NULL;
134210312Sjmallett		goto error;
135210312Sjmallett	}
136210312Sjmallett	err = octusb_init(&sc->sc_dci);
137210312Sjmallett	if (!err) {
138210312Sjmallett		err = device_probe_and_attach(sc->sc_dci.sc_bus.bdev);
139210312Sjmallett	}
140210312Sjmallett	if (err) {
141210312Sjmallett		goto error;
142210312Sjmallett	}
143210312Sjmallett	return (0);
144210312Sjmallett
145210312Sjmalletterror:
146210312Sjmallett	octusb_octeon_detach(dev);
147210312Sjmallett	return (ENXIO);
148210312Sjmallett}
149210312Sjmallett
150210312Sjmallettstatic int
151210312Sjmallettoctusb_octeon_detach(device_t dev)
152210312Sjmallett{
153210312Sjmallett	struct octusb_octeon_softc *sc = device_get_softc(dev);
154210312Sjmallett	device_t bdev;
155210312Sjmallett	int err;
156210312Sjmallett
157210312Sjmallett	if (sc->sc_dci.sc_bus.bdev) {
158210312Sjmallett		bdev = sc->sc_dci.sc_bus.bdev;
159210312Sjmallett		device_detach(bdev);
160210312Sjmallett		device_delete_child(dev, bdev);
161210312Sjmallett	}
162210312Sjmallett	/* during module unload there are lots of children leftover */
163227849Shselasky	device_delete_children(dev);
164210312Sjmallett
165210312Sjmallett	if (sc->sc_dci.sc_irq_res && sc->sc_dci.sc_intr_hdl) {
166210312Sjmallett		/*
167210312Sjmallett		 * only call octusb_octeon_uninit() after octusb_octeon_init()
168210312Sjmallett		 */
169210312Sjmallett		octusb_uninit(&sc->sc_dci);
170210312Sjmallett
171210312Sjmallett		err = bus_teardown_intr(dev, sc->sc_dci.sc_irq_res,
172210312Sjmallett		    sc->sc_dci.sc_intr_hdl);
173210312Sjmallett		sc->sc_dci.sc_intr_hdl = NULL;
174210312Sjmallett	}
175210312Sjmallett	if (sc->sc_dci.sc_irq_res) {
176210312Sjmallett		bus_release_resource(dev, SYS_RES_IRQ, 0,
177210312Sjmallett		    sc->sc_dci.sc_irq_res);
178210312Sjmallett		sc->sc_dci.sc_irq_res = NULL;
179210312Sjmallett	}
180210312Sjmallett	usb_bus_mem_free_all(&sc->sc_dci.sc_bus, NULL);
181210312Sjmallett
182210312Sjmallett	return (0);
183210312Sjmallett}
184210312Sjmallett
185210312Sjmallettstatic device_method_t octusb_octeon_methods[] = {
186210312Sjmallett	/* Device interface */
187210312Sjmallett	DEVMETHOD(device_identify, octusb_octeon_identify),
188210312Sjmallett	DEVMETHOD(device_probe, octusb_octeon_probe),
189210312Sjmallett	DEVMETHOD(device_attach, octusb_octeon_attach),
190210312Sjmallett	DEVMETHOD(device_detach, octusb_octeon_detach),
191228483Shselasky	DEVMETHOD(device_resume, bus_generic_resume),
192228483Shselasky	DEVMETHOD(device_suspend, bus_generic_suspend),
193228483Shselasky	DEVMETHOD(device_shutdown, bus_generic_shutdown),
194210312Sjmallett
195227843Smarius	DEVMETHOD_END
196210312Sjmallett};
197210312Sjmallett
198210312Sjmallettstatic driver_t octusb_octeon_driver = {
199228483Shselasky	.name = "octusb",
200228483Shselasky	.methods = octusb_octeon_methods,
201228483Shselasky	.size = sizeof(struct octusb_octeon_softc),
202210312Sjmallett};
203210312Sjmallett
204210312Sjmallettstatic devclass_t octusb_octeon_devclass;
205210312Sjmallett
206210312SjmallettDRIVER_MODULE(octusb, ciu, octusb_octeon_driver, octusb_octeon_devclass, 0, 0);
207